diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2020-11-03 12:38:38 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2020-11-03 12:38:38 +0000 |
commit | 9d8007c5342dcdd324af06af8ca18f6ea2974af1 (patch) | |
tree | fcfc08ec92b731594fc96c586e1207bccce2624d | |
parent | 54da8008995f7fa57f39a49a35f3f75080a4ce69 (diff) | |
parent | cbcaa00003cf5a4597460dbb5f8cb9f992e939e7 (diff) | |
download | ml-9d8007c5342dcdd324af06af8ca18f6ea2974af1.tar.gz |
Merge "Migrate NNAPI runtime to canonical types"
148 files changed, 6029 insertions, 5679 deletions
diff --git a/nn/common/Android.bp b/nn/common/Android.bp index 202c69ed1..10f97a219 100644 --- a/nn/common/Android.bp +++ b/nn/common/Android.bp @@ -109,6 +109,12 @@ cc_library_static { ], whole_static_libs: [ "libarect", + "neuralnetworks_types", + "neuralnetworks_utils_hal_1_0", // TODO(b/160669116): Remove VNDK dependencies. + "neuralnetworks_utils_hal_1_1", + "neuralnetworks_utils_hal_1_2", + "neuralnetworks_utils_hal_1_3", + "neuralnetworks_utils_hal_common", ], cflags: [ "-DTF_LITE_DISABLE_X86_NEON", @@ -204,6 +210,12 @@ cc_library_static { whole_static_libs: [ "libarect", "libtflite_kernel_utils", + "neuralnetworks_types", + "neuralnetworks_utils_hal_1_0", // TODO(b/160669116): Remove VNDK dependencies. + "neuralnetworks_utils_hal_1_1", + "neuralnetworks_utils_hal_1_2", + "neuralnetworks_utils_hal_1_3", + "neuralnetworks_utils_hal_common", "philox_random", ], static_libs: [ @@ -232,6 +244,12 @@ cc_defaults { name: "neuralnetworks_utils_defaults", host_supported: true, vendor_available: true, + apex_available: [ + "//apex_available:platform", + "com.android.neuralnetworks", + "test_com.android.neuralnetworks", + ], + min_sdk_version: "30", cflags: [ "-Wall", "-Werror", diff --git a/nn/common/BufferTracker.cpp b/nn/common/BufferTracker.cpp index e6b8d947d..cb2a326f2 100644 --- a/nn/common/BufferTracker.cpp +++ b/nn/common/BufferTracker.cpp @@ -28,11 +28,10 @@ #include "CpuExecutor.h" #include "HalInterfaces.h" #include "Utils.h" +#include "nnapi/TypeUtils.h" namespace android::nn { -using namespace hal; - std::shared_ptr<ManagedBuffer> ManagedBuffer::create(uint32_t size, std::set<PreparedModelRole> roles, const Operand& operand) { @@ -40,7 +39,7 @@ std::shared_ptr<ManagedBuffer> ManagedBuffer::create(uint32_t size, if (buffer == nullptr) { return nullptr; } - if (isExtensionOperandType(operand.type)) { + if (isExtension(operand.type)) { LOG(ERROR) << "ManagedBuffer cannot handle extension operands."; return nullptr; } @@ -55,19 +54,18 @@ ManagedBuffer::ManagedBuffer(std::unique_ptr<uint8_t[]> buffer, uint32_t size, kOperandType(operand.type), kInitialDimensions(operand.dimensions), mUpdatedDimensions(operand.dimensions) { - CHECK(!isExtensionOperandType(kOperandType)); + CHECK(!isExtension(kOperandType)); } ErrorStatus ManagedBuffer::validateRequest(uint32_t poolIndex, const Request& request, - const IPreparedModel* preparedModel) const { + const V1_3::IPreparedModel* preparedModel) const { CHECK_LT(poolIndex, request.pools.size()); - CHECK(request.pools[poolIndex].getDiscriminator() == - Request::MemoryPool::hidl_discriminator::token); + CHECK(std::holds_alternative<Request::MemoryDomainToken>(request.pools[poolIndex])); std::lock_guard<std::mutex> guard(mMutex); bool usedAsInput = false, usedAsOutput = false; for (uint32_t i = 0; i < request.inputs.size(); i++) { - if (request.inputs[i].hasNoValue) continue; + if (request.inputs[i].lifetime != Request::Argument::LifeTime::POOL) continue; if (request.inputs[i].location.poolIndex != poolIndex) continue; // Validate if the input role is specified during allocation. if (kRoles.count({preparedModel, IOType::INPUT, i}) == 0) { @@ -89,7 +87,7 @@ ErrorStatus ManagedBuffer::validateRequest(uint32_t poolIndex, const Request& re usedAsInput = true; } for (uint32_t i = 0; i < request.outputs.size(); i++) { - if (request.outputs[i].hasNoValue) continue; + if (request.outputs[i].lifetime != Request::Argument::LifeTime::POOL) continue; if (request.outputs[i].location.poolIndex != poolIndex) continue; if (usedAsInput || usedAsOutput) { LOG(ERROR) << "ManagedBuffer::validateRequest -- using the same device memory for " diff --git a/nn/common/CpuExecutor.cpp b/nn/common/CpuExecutor.cpp index 5dd41ad8e..4ca9709d6 100644 --- a/nn/common/CpuExecutor.cpp +++ b/nn/common/CpuExecutor.cpp @@ -40,13 +40,14 @@ #include "Operations.h" #include "OperationsUtils.h" #include "Tracing.h" +#include "nnapi/TypeUtils.h" namespace android { namespace nn { -namespace { +using ::android::hidl::memory::V1_0::IMemory; -using namespace hal; +namespace { class OperationExecutionContext : public IOperationExecutionContext { DISALLOW_IMPLICIT_CONSTRUCTORS(OperationExecutionContext); @@ -59,7 +60,7 @@ class OperationExecutionContext : public IOperationExecutionContext { OperandType getInputType(uint32_t index) const override; Shape getInputShape(uint32_t index) const override; const void* getInputBuffer(uint32_t index) const override; - const OperandExtraParams getInputExtraParams(uint32_t index) const override; + const Operand::ExtraParams& getInputExtraParams(uint32_t index) const override; uint32_t getNumOutputs() const override; OperandType getOutputType(uint32_t index) const override; @@ -117,7 +118,7 @@ const void* OperationExecutionContext::getInputBuffer(uint32_t index) const { return getInputInfo(index)->buffer; } -const OperandExtraParams OperationExecutionContext::getInputExtraParams(uint32_t index) const { +const Operand::ExtraParams& OperationExecutionContext::getInputExtraParams(uint32_t index) const { return getInputInfo(index)->extraParams; } @@ -154,7 +155,7 @@ int OperationExecutionContext::getResultCode() const { bool setInfoAndAllocateIfNeeded(RunTimeOperandInfo* info, const Shape& shape, int* result) { // For user-provided model output operands, the parameters must match the Shape // calculated from the preparation step. - if (info->lifetime == OperandLifeTime::SUBGRAPH_OUTPUT) { + if (info->lifetime == Operand::LifeTime::SUBGRAPH_OUTPUT) { if (info->type != shape.type) { LOG(ERROR) << "Invalid type for model output"; *result = ANEURALNETWORKS_OP_FAILED; @@ -191,7 +192,7 @@ bool setInfoAndAllocateIfNeeded(RunTimeOperandInfo* info, const Shape& shape, in // TODO(b/153081229): We bypass the overflow check on extension operands because we do not know // the sizes of extension types. - if (!isExtensionOperandType(info->type) && + if (!isExtension(info->type) && nonExtensionOperandSizeOfDataOverflowsUInt32(info->type, info->dimensions)) { LOG(ERROR) << "Operand data size overflows uint32_t"; *result = ANEURALNETWORKS_OP_FAILED; @@ -199,9 +200,9 @@ bool setInfoAndAllocateIfNeeded(RunTimeOperandInfo* info, const Shape& shape, in } // Allocate the buffer only if the combined dimension is fully specified - if (info->buffer == nullptr && (info->lifetime == OperandLifeTime::TEMPORARY_VARIABLE || - info->lifetime == OperandLifeTime::SUBGRAPH_OUTPUT)) { - if (isExtensionOperandType(info->type)) { + if (info->buffer == nullptr && (info->lifetime == Operand::LifeTime::TEMPORARY_VARIABLE || + info->lifetime == Operand::LifeTime::SUBGRAPH_OUTPUT)) { + if (isExtension(info->type)) { LOG(ERROR) << "Cannot allocate a variable of an extension type"; *result = ANEURALNETWORKS_OP_FAILED; return false; @@ -232,21 +233,21 @@ bool OperationExecutionContext::setOutputShape(uint32_t index, const Shape& shap } bool OperationExecutionContext::isOmittedInput(uint32_t index) const { - return getInputInfo(index)->lifetime == OperandLifeTime::NO_VALUE; + return getInputInfo(index)->lifetime == Operand::LifeTime::NO_VALUE; } bool OperationExecutionContext::isOmittedOutput(uint32_t index) const { - return getOutputInfo(index)->lifetime == OperandLifeTime::NO_VALUE; + return getOutputInfo(index)->lifetime == Operand::LifeTime::NO_VALUE; } bool OperationExecutionContext::checkNoOmittedOperand() const { for (uint32_t i = 0; i < operation->inputs.size(); i++) { - NN_RET_CHECK(!isOmittedInput(i)) << getOperationName(operation->type) << " input operand " - << i << " is required but missing."; + NN_RET_CHECK(!isOmittedInput(i)) + << operation->type << " input operand " << i << " is required but missing."; } for (uint32_t i = 0; i < operation->outputs.size(); i++) { - NN_RET_CHECK(!isOmittedOutput(i)) << getOperationName(operation->type) << " output operand " - << i << " is required but missing."; + NN_RET_CHECK(!isOmittedOutput(i)) + << operation->type << " output operand " << i << " is required but missing."; } return true; } @@ -256,9 +257,8 @@ bool OperationExecutionContext::checkNoZeroSizedInput() const { if (isOmittedInput(i)) continue; for (uint32_t j = 0; j < getInputInfo(i)->dimensions.size(); j++) { NN_RET_CHECK_NE(getInputInfo(i)->dimensions[j], 0) - << getOperationName(operation->type) - << " does not support zero-sized tensor, but input " << i << " dimension " << j - << " is 0."; + << operation->type << " does not support zero-sized tensor, but input " << i + << " dimension " << j << " is 0."; } } return true; @@ -273,8 +273,8 @@ bool OperationExecutionContext::checkNoZeroSizedInput() const { // when the RunTimePoolInfo is destroyed or is assigned to. class RunTimePoolInfo::RunTimePoolInfoImpl { public: - RunTimePoolInfoImpl(const hidl_memory& hidlMemory, uint8_t* buffer, const sp<IMemory>& memory, - AHardwareBuffer* hardwareBuffer, uint32_t size); + RunTimePoolInfoImpl(const hardware::hidl_memory& hidlMemory, uint8_t* buffer, + const sp<IMemory>& memory, AHardwareBuffer* hardwareBuffer, uint32_t size); // rule of five... ~RunTimePoolInfoImpl(); @@ -288,10 +288,10 @@ class RunTimePoolInfo::RunTimePoolInfoImpl { bool flush() const; - const hidl_memory& getHidlMemory() const { return mHidlMemory; } + const hardware::hidl_memory& getHidlMemory() const { return mHidlMemory; } private: - const hidl_memory mHidlMemory; // always used + const hardware::hidl_memory mHidlMemory; // always used uint8_t* const mBuffer = nullptr; // always used const sp<IMemory> mMemory; // only used when hidlMemory.name() == "ashmem" AHardwareBuffer* @@ -299,7 +299,7 @@ class RunTimePoolInfo::RunTimePoolInfoImpl { const uint32_t mSize; }; -RunTimePoolInfo::RunTimePoolInfoImpl::RunTimePoolInfoImpl(const hidl_memory& hidlMemory, +RunTimePoolInfo::RunTimePoolInfoImpl::RunTimePoolInfoImpl(const hardware::hidl_memory& hidlMemory, uint8_t* buffer, const sp<IMemory>& memory, AHardwareBuffer* hardwareBuffer, @@ -352,8 +352,8 @@ bool RunTimePoolInfo::RunTimePoolInfoImpl::flush() const { // TODO: short term, make share memory mapping and updating a utility function. // TODO: long term, implement mmap_fd as a hidl IMemory service. -std::optional<RunTimePoolInfo> RunTimePoolInfo::createFromHidlMemory( - const hidl_memory& hidlMemory) { +std::optional<RunTimePoolInfo> RunTimePoolInfo::createFromMemory(const Memory& canonicalMemory) { + hardware::hidl_memory hidlMemory = convertToV1_0(canonicalMemory); uint8_t* buffer = nullptr; sp<IMemory> memory; AHardwareBuffer* hardwareBuffer = nullptr; @@ -423,8 +423,8 @@ std::optional<RunTimePoolInfo> RunTimePoolInfo::createFromHidlMemory( } RunTimePoolInfo RunTimePoolInfo::createFromExistingBuffer(uint8_t* buffer, uint32_t size) { - const auto impl = std::make_shared<const RunTimePoolInfoImpl>(hidl_memory{}, buffer, nullptr, - nullptr, size); + const auto impl = std::make_shared<const RunTimePoolInfoImpl>(hardware::hidl_memory{}, buffer, + nullptr, nullptr, size); return {impl}; } @@ -443,17 +443,17 @@ bool RunTimePoolInfo::flush() const { return mImpl->flush(); } -const hidl_memory& RunTimePoolInfo::getHidlMemory() const { - return mImpl->getHidlMemory(); +Memory RunTimePoolInfo::getMemory() const { + return uncheckedConvert(mImpl->getHidlMemory()); } -bool setRunTimePoolInfosFromHidlMemories(std::vector<RunTimePoolInfo>* poolInfos, - const hidl_vec<hidl_memory>& pools) { +bool setRunTimePoolInfosFromCanonicalMemories(std::vector<RunTimePoolInfo>* poolInfos, + const std::vector<Memory>& pools) { CHECK(poolInfos != nullptr); poolInfos->clear(); poolInfos->reserve(pools.size()); for (const auto& pool : pools) { - if (std::optional<RunTimePoolInfo> poolInfo = RunTimePoolInfo::createFromHidlMemory(pool)) { + if (std::optional<RunTimePoolInfo> poolInfo = RunTimePoolInfo::createFromMemory(pool)) { poolInfos->push_back(*poolInfo); } else { LOG(ERROR) << "Could not map pools"; @@ -465,18 +465,18 @@ bool setRunTimePoolInfosFromHidlMemories(std::vector<RunTimePoolInfo>* poolInfos } bool setRunTimePoolInfosFromMemoryPools(std::vector<RunTimePoolInfo>* poolInfos, - const hidl_vec<Request::MemoryPool>& pools) { + const std::vector<Request::MemoryPool>& pools) { CHECK(poolInfos != nullptr); poolInfos->clear(); poolInfos->reserve(pools.size()); for (const auto& pool : pools) { - if (pool.getDiscriminator() != Request::MemoryPool::hidl_discriminator::hidlMemory) { + if (!std::holds_alternative<Memory>(pool)) { LOG(ERROR) << "Unknown memory token"; poolInfos->clear(); return false; } if (std::optional<RunTimePoolInfo> poolInfo = - RunTimePoolInfo::createFromHidlMemory(pool.hidlMemory())) { + RunTimePoolInfo::createFromMemory(std::get<Memory>(pool))) { poolInfos->push_back(*poolInfo); } else { LOG(ERROR) << "Could not map pools"; @@ -522,7 +522,7 @@ static bool convertToNhwc(RunTimeOperandInfo& to, const RunTimeOperandInfo& from LOG(ERROR) << "Error converting a non-4-D tensor to NHWC layout"; return false; } - to.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + to.lifetime = Operand::LifeTime::TEMPORARY_VARIABLE; if (data_layout) { // convert dimensions Shape inShape = from.shape(); @@ -628,7 +628,7 @@ static void consumeOperationInputs(const std::vector<uint32_t>& inputs, // that are inputs to an operation. static void freeUnusedSubgraphOperands(std::vector<RunTimeOperandInfo>* operands) { for (auto& info : *operands) { - if (info.lifetime == OperandLifeTime::TEMPORARY_VARIABLE && info.numberOfUsesLeft == 0 && + if (info.lifetime == Operand::LifeTime::TEMPORARY_VARIABLE && info.numberOfUsesLeft == 0 && info.buffer != nullptr) { delete[] info.buffer; info.buffer = nullptr; @@ -642,8 +642,8 @@ int CpuExecutor::run(const Model& model, const Request& request, const std::vector<RunTimePoolInfo>& modelPoolInfos, const std::vector<RunTimePoolInfo>& requestPoolInfos) { NNTRACE_CPU(NNTRACE_PHASE_EXECUTION, "run"); - VLOG(CPUEXE) << "CpuExecutor::run() with request(" << SHOW_IF_DEBUG(toString(request)) << ")"; - mModelOperandValues = &model.operandValues; + VLOG(CPUEXE) << "CpuExecutor::run() with request(" << SHOW_IF_DEBUG(request) << ")"; + mModelOperandValues = model.operandValues.data(); mModelPoolInfos = &modelPoolInfos; mReferencedSubgraphs = &model.referenced; @@ -680,8 +680,8 @@ int CpuExecutor::run(const Model& model, const Request& request, return result; } -int CpuExecutor::executeSubgraph(const Subgraph& subgraph, RunTimeOperandInfo* operands) { - VLOG(CPUEXE) << "CpuExecutor::executeSubgraph " << toString(subgraph); +int CpuExecutor::executeSubgraph(const Model::Subgraph& subgraph, RunTimeOperandInfo* operands) { + VLOG(CPUEXE) << "CpuExecutor::executeSubgraph " << subgraph; // The graph has serialized the operation in execution order. for (const auto& operation : subgraph.operations) { NN_RETURN_IF_ERROR(executeOperation(operation, operands)); @@ -689,10 +689,12 @@ int CpuExecutor::executeSubgraph(const Subgraph& subgraph, RunTimeOperandInfo* o return ANEURALNETWORKS_NO_ERROR; } -std::vector<RunTimeOperandInfo> CpuExecutor::initializeRunTimeInfo(const Subgraph& subgraph) { +std::vector<RunTimeOperandInfo> CpuExecutor::initializeRunTimeInfo( + const Model::Subgraph& subgraph) { VLOG(CPUEXE) << "CpuExecutor::initializeRunTimeInfo"; const size_t count = subgraph.operands.size(); std::vector<RunTimeOperandInfo> operands(count); + std::vector<uint32_t> numberOfConsumers = countNumberOfConsumers(count, subgraph.operations); for (size_t i = 0; i < count; i++) { const Operand& from = subgraph.operands[i]; RunTimeOperandInfo& to = operands[i]; @@ -704,15 +706,15 @@ std::vector<RunTimeOperandInfo> CpuExecutor::initializeRunTimeInfo(const Subgrap to.lifetime = from.lifetime; to.extraParams = from.extraParams; switch (from.lifetime) { - case OperandLifeTime::TEMPORARY_VARIABLE: + case Operand::LifeTime::TEMPORARY_VARIABLE: to.buffer = nullptr; - to.numberOfUsesLeft = from.numberOfConsumers; + to.numberOfUsesLeft = numberOfConsumers[i]; break; - case OperandLifeTime::CONSTANT_COPY: - to.buffer = const_cast<uint8_t*>(&(*mModelOperandValues)[from.location.offset]); + case Operand::LifeTime::CONSTANT_COPY: + to.buffer = const_cast<uint8_t*>(mModelOperandValues + from.location.offset); to.numberOfUsesLeft = 0; break; - case OperandLifeTime::CONSTANT_REFERENCE: { + case Operand::LifeTime::CONSTANT_REFERENCE: { auto poolIndex = from.location.poolIndex; CHECK_LT(poolIndex, mModelPoolInfos->size()); auto& r = (*mModelPoolInfos)[poolIndex]; @@ -720,16 +722,21 @@ std::vector<RunTimeOperandInfo> CpuExecutor::initializeRunTimeInfo(const Subgrap to.numberOfUsesLeft = 0; break; } - case OperandLifeTime::SUBGRAPH: { + case Operand::LifeTime::SUBGRAPH: { auto subgraphIndex = from.location.offset; CHECK_LT(subgraphIndex, mReferencedSubgraphs->size()); to.buffer = reinterpret_cast<uint8_t*>( - const_cast<Subgraph*>(&(*mReferencedSubgraphs)[subgraphIndex])); + const_cast<Model::Subgraph*>(&(*mReferencedSubgraphs)[subgraphIndex])); + to.numberOfUsesLeft = 0; + } break; + case Operand::LifeTime::POINTER: { + to.buffer = reinterpret_cast<uint8_t*>( + const_cast<void*>(std::get<const void*>(from.location.pointer))); to.numberOfUsesLeft = 0; } break; - case OperandLifeTime::SUBGRAPH_INPUT: - case OperandLifeTime::SUBGRAPH_OUTPUT: - case OperandLifeTime::NO_VALUE: + case Operand::LifeTime::SUBGRAPH_INPUT: + case Operand::LifeTime::SUBGRAPH_OUTPUT: + case Operand::LifeTime::NO_VALUE: to.buffer = nullptr; to.numberOfUsesLeft = 0; break; @@ -739,15 +746,15 @@ std::vector<RunTimeOperandInfo> CpuExecutor::initializeRunTimeInfo(const Subgrap } void CpuExecutor::updateForArguments(const std::vector<uint32_t>& indexes, - const hal::hidl_vec<hal::RequestArgument>& arguments, + const std::vector<Request::Argument>& arguments, const std::vector<RunTimePoolInfo>& requestPoolInfos, RunTimeOperandInfo* operands) { CHECK_EQ(indexes.size(), arguments.size()); for (size_t i = 0; i < indexes.size(); i++) { const uint32_t operandIndex = indexes[i]; - const RequestArgument& from = arguments[i]; + const Request::Argument& from = arguments[i]; RunTimeOperandInfo& to = operands[operandIndex]; - if (from.dimensions.size() > 0) { + if (!from.dimensions.empty()) { // It's the responsibility of the caller to validate that // from.dimensions only modifies the dimensions that were // unspecified in the model. That's the case in SampleDriver.cpp @@ -755,8 +762,8 @@ void CpuExecutor::updateForArguments(const std::vector<uint32_t>& indexes, // TODO make sure that's the case for the default CPU path. to.dimensions = from.dimensions; } - if (from.hasNoValue) { - to.lifetime = OperandLifeTime::NO_VALUE; + if (from.lifetime == Request::Argument::LifeTime::NO_VALUE) { + to.lifetime = Operand::LifeTime::NO_VALUE; CHECK(to.buffer == nullptr); to.length = 0; } else { @@ -793,9 +800,9 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo return result; } - // VLOG(CPUEXE) << "CpuExecutor::executeOperation(" << toString(operation) << ")"; - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + // VLOG(CPUEXE) << "CpuExecutor::executeOperation(" << operation << ")"; + const std::vector<uint32_t>& ins = operation.inputs; + const std::vector<uint32_t>& outs = operation.outputs; bool success = false; int result = ANEURALNETWORKS_NO_ERROR; @@ -807,29 +814,30 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo auto allParametersPresent = [&operation, &operands, &ins, &outs](size_t requiredIns, size_t requiredOuts) -> bool { auto verify = [&operation, &operands](size_t requiredCount, - const hidl_vec<uint32_t>& indexes, + const std::vector<uint32_t>& indexes, const char* type) -> bool { size_t actualCount = indexes.size(); if (actualCount != requiredCount) { - LOG(ERROR) << getOperationName(operation.type) << ": Invalid number of " << type - << " operands. Got " << actualCount << " of " << requiredCount; + LOG(ERROR) << operation.type << ": Invalid number of " << type << " operands. Got " + << actualCount << " of " << requiredCount; return false; } for (size_t i = 0; i < actualCount; i++) { - if (operands[indexes[i]].lifetime == OperandLifeTime::NO_VALUE) { - LOG(ERROR) << getOperationName(operation.type) << " " << type << " operand " - << i << " is required but missing."; + if (operands[indexes[i]].lifetime == Operand::LifeTime::NO_VALUE) { + LOG(ERROR) << operation.type << " " << type << " operand " << i + << " is required but missing."; return false; } } return true; }; - auto verifyNoZeroSizedInputs = [&operation, &operands](const hidl_vec<uint32_t>& indexes) { + auto verifyNoZeroSizedInputs = [&operation, + &operands](const std::vector<uint32_t>& indexes) { for (size_t i = 0; i < indexes.size(); i++) { for (size_t j = 0; j < operands[indexes[i]].dimensions.size(); j++) { if (operands[indexes[i]].dimensions[j] == 0) { - LOG(ERROR) << getOperationName(operation.type) + LOG(ERROR) << operation.type << " does not support zero-sized tensor, but input " << i << " dimension " << j << " is zero."; return false; @@ -882,7 +890,7 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo success = false; break; } - output_tmp.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + output_tmp.lifetime = Operand::LifeTime::TEMPORARY_VARIABLE; output_tmp.buffer = data_layout ? nullptr : output.buffer; output_tmp.length = data_layout ? 0 : output.length; if (!depthToSpacePrepare(input_tmp.shape(), blockSize, &outShape) || @@ -946,7 +954,7 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo success = false; break; } - output_tmp.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + output_tmp.lifetime = Operand::LifeTime::TEMPORARY_VARIABLE; output_tmp.buffer = data_layout ? nullptr : output.buffer; output_tmp.length = data_layout ? 0 : output.length; @@ -1167,7 +1175,7 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo success = false; break; } - output_tmp.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + output_tmp.lifetime = Operand::LifeTime::TEMPORARY_VARIABLE; output_tmp.buffer = data_layout ? nullptr : output.buffer; output_tmp.length = data_layout ? 0 : output.length; @@ -1239,7 +1247,7 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo success = false; break; } - output_tmp.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + output_tmp.lifetime = Operand::LifeTime::TEMPORARY_VARIABLE; output_tmp.buffer = data_layout ? nullptr : output.buffer; output_tmp.length = data_layout ? 0 : output.length; @@ -1558,7 +1566,7 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo success = false; break; } - output_tmp.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; + output_tmp.lifetime = Operand::LifeTime::TEMPORARY_VARIABLE; output_tmp.buffer = data_layout ? nullptr : output.buffer; output_tmp.length = data_layout ? 0 : output.length; @@ -1605,7 +1613,8 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo success = groupedConvQuant8PerChannel( reinterpret_cast<const uint8_t*>(input_tmp.buffer), input_tmp.shape(), reinterpret_cast<const int8_t*>(filter.buffer), filter.shape(), - filter.extraParams.channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>(filter.extraParams) + .scales.data(), reinterpret_cast<const int32_t*>(bias.buffer), bias.shape(), padding_left, padding_right, padding_top, padding_bottom, stride_width, stride_height, numGroups, activation, @@ -1624,7 +1633,8 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo success = groupedConvQuant8PerChannel( reinterpret_cast<const int8_t*>(input_tmp.buffer), input_tmp.shape(), reinterpret_cast<const int8_t*>(filter.buffer), filter.shape(), - filter.extraParams.channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>(filter.extraParams) + .scales.data(), reinterpret_cast<const int32_t*>(bias.buffer), bias.shape(), padding_left, padding_right, padding_top, padding_bottom, stride_width, stride_height, numGroups, activation, @@ -1703,11 +1713,10 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo const OperationRegistration* operationRegistration = mOperationResolver->findOperation(operation.type); if (operationRegistration == nullptr) { - LOG(ERROR) << getOperationName(operation.type) << " not registered"; + LOG(ERROR) << operation.type << " not registered"; } else if (operationRegistration->prepare == nullptr || operationRegistration->execute == nullptr) { - LOG(ERROR) << "Incomplete operation registration: " - << getOperationName(operation.type); + LOG(ERROR) << "Incomplete operation registration: " << operation.type; } else { OperationExecutionContext context(&operation, operands); success = operationRegistration->flags.allowOmittedOperand || @@ -1724,7 +1733,7 @@ int CpuExecutor::executeOperation(const Operation& operation, RunTimeOperandInfo result = ANEURALNETWORKS_OP_FAILED; } if (result != ANEURALNETWORKS_NO_ERROR) { - LOG(ERROR) << getOperationName(operation.type) << " failed."; + LOG(ERROR) << operation.type << " failed."; } consumeOperationInputs(ins, operands); @@ -1753,7 +1762,8 @@ int CpuExecutor::executeIfOperation(const Operation& operation, RunTimeOperandIn const uint32_t branchInputIndex = condValue ? op::kThenModelOperand : op::kElseModelOperand; const RunTimeOperandInfo& branchOperand = operands[operation.inputs[branchInputIndex]]; - const Subgraph& branchSubgraph = *reinterpret_cast<const Subgraph*>(branchOperand.buffer); + const Model::Subgraph& branchSubgraph = + *reinterpret_cast<const Model::Subgraph*>(branchOperand.buffer); std::vector<RunTimeOperandInfo> branchOperands = initializeRunTimeInfo(branchSubgraph); // Initialize inner input and output operands from outer operands. @@ -1783,8 +1793,10 @@ int CpuExecutor::executeWhileOperation(const Operation& operation, RunTimeOperan namespace op = operation_while; const RunTimeOperandInfo& condModelOperand = operands[operation.inputs[op::kCondModelOperand]]; const RunTimeOperandInfo& bodyModelOperand = operands[operation.inputs[op::kBodyModelOperand]]; - const Subgraph& condSubgraph = *reinterpret_cast<const Subgraph*>(condModelOperand.buffer); - const Subgraph& bodySubgraph = *reinterpret_cast<const Subgraph*>(bodyModelOperand.buffer); + const Model::Subgraph& condSubgraph = + *reinterpret_cast<const Model::Subgraph*>(condModelOperand.buffer); + const Model::Subgraph& bodySubgraph = + *reinterpret_cast<const Model::Subgraph*>(bodyModelOperand.buffer); std::vector<RunTimeOperandInfo> condOperands = initializeRunTimeInfo(condSubgraph); std::vector<RunTimeOperandInfo> bodyOperands = initializeRunTimeInfo(bodySubgraph); @@ -1916,7 +1928,7 @@ void CpuExecutor::setOutputShapes(const std::vector<uint32_t>& outputIndexes, mOutputShapes[i].dimensions = from.dimensions; mOutputShapes[i].isSufficient = from.isSufficient(); VLOG(EXECUTION) << "CpuExecutor::setOutputShapes: mOutputShapes[" << i - << "] = " << toString(mOutputShapes[i]); + << "] = " << mOutputShapes[i]; } } diff --git a/nn/common/ExecutionBurstController.cpp b/nn/common/ExecutionBurstController.cpp index e195e7d31..bb1c08f6b 100644 --- a/nn/common/ExecutionBurstController.cpp +++ b/nn/common/ExecutionBurstController.cpp @@ -36,8 +36,6 @@ namespace android::nn { namespace { -using namespace hal; - using V1_2::FmqRequestDatum; using V1_2::FmqResultDatum; using V1_2::IBurstCallback; @@ -45,10 +43,10 @@ using V1_2::IBurstContext; using FmqRequestDescriptor = hardware::MQDescriptorSync<FmqRequestDatum>; using FmqResultDescriptor = hardware::MQDescriptorSync<FmqResultDatum>; -constexpr Timing kNoTiming = {std::numeric_limits<uint64_t>::max(), - std::numeric_limits<uint64_t>::max()}; +constexpr V1_2::Timing kNoTiming12 = {std::numeric_limits<uint64_t>::max(), + std::numeric_limits<uint64_t>::max()}; -class BurstContextDeathHandler : public hidl_death_recipient { +class BurstContextDeathHandler : public hardware::hidl_death_recipient { public: using Callback = std::function<void()>; @@ -68,7 +66,7 @@ class BurstContextDeathHandler : public hidl_death_recipient { } // anonymous namespace // serialize a request into a packet -std::vector<FmqRequestDatum> serialize(const V1_0::Request& request, MeasureTiming measure, +std::vector<FmqRequestDatum> serialize(const V1_0::Request& request, V1_2::MeasureTiming measure, const std::vector<int32_t>& slots) { // count how many elements need to be sent for a request size_t count = 2 + request.inputs.size() + request.outputs.size() + request.pools.size(); @@ -149,11 +147,11 @@ std::vector<FmqRequestDatum> serialize(const V1_0::Request& request, MeasureTimi } // deserialize a packet into the result -std::optional<std::tuple<V1_0::ErrorStatus, std::vector<OutputShape>, Timing>> deserialize( - const std::vector<FmqResultDatum>& data) { +std::optional<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::Timing>> +deserialize(const std::vector<FmqResultDatum>& data) { using discriminator = FmqResultDatum::hidl_discriminator; - std::vector<OutputShape> outputShapes; + std::vector<V1_2::OutputShape> outputShapes; size_t index = 0; // validate packet information @@ -218,7 +216,7 @@ std::optional<std::tuple<V1_0::ErrorStatus, std::vector<OutputShape>, Timing>> d } // unpackage execution timing - const Timing timing = data[index].executionTiming(); + const V1_2::Timing timing = data[index].executionTiming(); index++; // validate packet information @@ -254,7 +252,7 @@ ResultChannelReceiver::ResultChannelReceiver(std::unique_ptr<FmqResultChannel> f std::chrono::microseconds pollingTimeWindow) : mFmqResultChannel(std::move(fmqResultChannel)), kPollingTimeWindow(pollingTimeWindow) {} -std::optional<std::tuple<V1_0::ErrorStatus, std::vector<OutputShape>, Timing>> +std::optional<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::Timing>> ResultChannelReceiver::getBlocking() { const auto packet = getPacketBlocking(); if (!packet) { @@ -275,7 +273,8 @@ void ResultChannelReceiver::invalidate() { // TODO: look for a different/better way to signal/notify the futex to // wake up any thread waiting on it FmqResultDatum datum; - datum.packetInformation({/*.packetSize=*/0, /*.errorStatus=*/V1_0::ErrorStatus::GENERAL_FAILURE, + datum.packetInformation({/*.packetSize=*/0, + /*.errorStatus=*/V1_0::ErrorStatus::GENERAL_FAILURE, /*.numberOfOperands=*/0}); mFmqResultChannel->writeBlocking(&datum, 1); } @@ -363,7 +362,7 @@ RequestChannelSender::create(size_t channelLength) { RequestChannelSender::RequestChannelSender(std::unique_ptr<FmqRequestChannel> fmqRequestChannel) : mFmqRequestChannel(std::move(fmqRequestChannel)) {} -bool RequestChannelSender::send(const V1_0::Request& request, MeasureTiming measure, +bool RequestChannelSender::send(const V1_0::Request& request, V1_2::MeasureTiming measure, const std::vector<int32_t>& slots) { const std::vector<FmqRequestDatum> serialized = serialize(request, measure, slots); return sendPacket(serialized); @@ -389,30 +388,31 @@ void RequestChannelSender::invalidate() { mValid = false; } -Return<void> ExecutionBurstController::ExecutionBurstCallback::getMemories( - const hidl_vec<int32_t>& slots, getMemories_cb cb) { +hardware::Return<void> ExecutionBurstController::ExecutionBurstCallback::getMemories( + const hardware::hidl_vec<int32_t>& slots, getMemories_cb cb) { std::lock_guard<std::mutex> guard(mMutex); // get all memories - hidl_vec<hidl_memory> memories(slots.size()); + hardware::hidl_vec<hardware::hidl_memory> memories(slots.size()); std::transform(slots.begin(), slots.end(), memories.begin(), [this](int32_t slot) { - return slot < mMemoryCache.size() ? mMemoryCache[slot] : hidl_memory{}; + return slot < mMemoryCache.size() ? mMemoryCache[slot] : hardware::hidl_memory{}; }); // ensure all memories are valid if (!std::all_of(memories.begin(), memories.end(), - [](const hidl_memory& memory) { return memory.valid(); })) { + [](const hardware::hidl_memory& memory) { return memory.valid(); })) { cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}); - return Void(); + return hardware::Void(); } // return successful cb(V1_0::ErrorStatus::NONE, std::move(memories)); - return Void(); + return hardware::Void(); } std::vector<int32_t> ExecutionBurstController::ExecutionBurstCallback::getSlots( - const hidl_vec<hidl_memory>& memories, const std::vector<intptr_t>& keys) { + const hardware::hidl_vec<hardware::hidl_memory>& memories, + const std::vector<intptr_t>& keys) { std::lock_guard<std::mutex> guard(mMutex); // retrieve (or bind) all slots corresponding to memories @@ -439,8 +439,8 @@ std::pair<bool, int32_t> ExecutionBurstController::ExecutionBurstCallback::freeM return {true, slot}; } -int32_t ExecutionBurstController::ExecutionBurstCallback::getSlotLocked(const hidl_memory& memory, - intptr_t key) { +int32_t ExecutionBurstController::ExecutionBurstCallback::getSlotLocked( + const hardware::hidl_memory& memory, intptr_t key) { auto iter = mMemoryIdToSlot.find(key); if (iter == mMemoryIdToSlot.end()) { const int32_t slot = allocateSlotLocked(); @@ -503,7 +503,7 @@ std::unique_ptr<ExecutionBurstController> ExecutionBurstController::create( // configure burst V1_0::ErrorStatus errorStatus; sp<IBurstContext> burstContext; - const Return<void> ret = preparedModel->configureExecutionBurst( + const hardware::Return<void> ret = preparedModel->configureExecutionBurst( callback, *requestChannelDescriptor, *resultChannelDescriptor, [&errorStatus, &burstContext](V1_0::ErrorStatus status, const sp<IBurstContext>& context) { @@ -539,7 +539,7 @@ std::unique_ptr<ExecutionBurstController> ExecutionBurstController::create( // proactively handle service crashes. If the linkToDeath call fails, // asynchronous calls are susceptible to hangs if the service crashes before // providing the response. - const Return<bool> deathHandlerRet = burstContext->linkToDeath(deathHandler, 0); + const hardware::Return<bool> deathHandlerRet = burstContext->linkToDeath(deathHandler, 0); if (!deathHandlerRet.isOk() || deathHandlerRet != true) { LOG(ERROR) << "ExecutionBurstController::create -- Failed to register a death recipient " "for the IBurstContext object."; @@ -555,7 +555,7 @@ ExecutionBurstController::ExecutionBurstController( const std::shared_ptr<RequestChannelSender>& requestChannelSender, const std::shared_ptr<ResultChannelReceiver>& resultChannelReceiver, const sp<IBurstContext>& burstContext, const sp<ExecutionBurstCallback>& callback, - const sp<hidl_death_recipient>& deathHandler) + const sp<hardware::hidl_death_recipient>& deathHandler) : mRequestChannelSender(requestChannelSender), mResultChannelReceiver(resultChannelReceiver), mBurstContext(burstContext), @@ -572,17 +572,17 @@ ExecutionBurstController::~ExecutionBurstController() { } } -static std::tuple<int, std::vector<OutputShape>, Timing, bool> getExecutionResult( - V1_0::ErrorStatus status, std::vector<OutputShape> outputShapes, Timing timing, +static std::tuple<int, std::vector<V1_2::OutputShape>, V1_2::Timing, bool> getExecutionResult( + V1_0::ErrorStatus status, std::vector<V1_2::OutputShape> outputShapes, V1_2::Timing timing, bool fallback) { auto [n, checkedOutputShapes, checkedTiming] = getExecutionResult(convertToV1_3(status), std::move(outputShapes), timing); - return {n, std::move(checkedOutputShapes), checkedTiming, fallback}; + return {n, convertToV1_2(checkedOutputShapes), convertToV1_2(checkedTiming), fallback}; } -std::tuple<int, std::vector<OutputShape>, Timing, bool> ExecutionBurstController::compute( - const V1_0::Request& request, MeasureTiming measure, - const std::vector<intptr_t>& memoryIds) { +std::tuple<int, std::vector<V1_2::OutputShape>, V1_2::Timing, bool> +ExecutionBurstController::compute(const V1_0::Request& request, V1_2::MeasureTiming measure, + const std::vector<intptr_t>& memoryIds) { // This is the first point when we know an execution is occurring, so begin // to collect systraces. Note that the first point we can begin collecting // systraces in ExecutionBurstServer is when the RequestChannelReceiver @@ -598,7 +598,7 @@ std::tuple<int, std::vector<OutputShape>, Timing, bool> ExecutionBurstController if (!success) { LOG(ERROR) << "Error sending FMQ packet"; // only use fallback execution path if the packet could not be sent - return getExecutionResult(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming, + return getExecutionResult(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming12, /*fallback=*/true); } @@ -607,7 +607,7 @@ std::tuple<int, std::vector<OutputShape>, Timing, bool> ExecutionBurstController if (!result) { LOG(ERROR) << "Error retrieving FMQ packet"; // only use fallback execution path if the packet could not be sent - return getExecutionResult(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming, + return getExecutionResult(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming12, /*fallback=*/false); } diff --git a/nn/common/ExecutionBurstServer.cpp b/nn/common/ExecutionBurstServer.cpp index 487cd9fad..67d4ccbda 100644 --- a/nn/common/ExecutionBurstServer.cpp +++ b/nn/common/ExecutionBurstServer.cpp @@ -35,16 +35,14 @@ namespace android::nn { namespace { -using namespace hal; - using hardware::MQDescriptorSync; using V1_2::FmqRequestDatum; using V1_2::FmqResultDatum; using V1_2::IBurstCallback; using V1_2::IBurstContext; -constexpr Timing kNoTiming = {std::numeric_limits<uint64_t>::max(), - std::numeric_limits<uint64_t>::max()}; +constexpr V1_2::Timing kNoTiming = {std::numeric_limits<uint64_t>::max(), + std::numeric_limits<uint64_t>::max()}; // DefaultBurstExecutorWithCache adapts an IPreparedModel so that it can be // used as an IBurstExecutorWithCache. Specifically, the cache simply stores the @@ -61,17 +59,17 @@ class DefaultBurstExecutorWithCache : public ExecutionBurstServer::IBurstExecuto return (it != mMemoryCache.end()) && it->second.valid(); } - void addCacheEntry(const hidl_memory& memory, int32_t slot) override { + void addCacheEntry(const hardware::hidl_memory& memory, int32_t slot) override { mMemoryCache[slot] = memory; } void removeCacheEntry(int32_t slot) override { mMemoryCache.erase(slot); } - std::tuple<V1_0::ErrorStatus, hidl_vec<OutputShape>, Timing> execute( + std::tuple<V1_0::ErrorStatus, hardware::hidl_vec<V1_2::OutputShape>, V1_2::Timing> execute( const V1_0::Request& request, const std::vector<int32_t>& slots, - MeasureTiming measure) override { + V1_2::MeasureTiming measure) override { // convert slots to pools - hidl_vec<hidl_memory> pools(slots.size()); + hardware::hidl_vec<hardware::hidl_memory> pools(slots.size()); std::transform(slots.begin(), slots.end(), pools.begin(), [this](int32_t slot) { return mMemoryCache[slot]; }); @@ -81,18 +79,20 @@ class DefaultBurstExecutorWithCache : public ExecutionBurstServer::IBurstExecuto // setup execution V1_0::ErrorStatus returnedStatus = V1_0::ErrorStatus::GENERAL_FAILURE; - hidl_vec<OutputShape> returnedOutputShapes; - Timing returnedTiming; + hardware::hidl_vec<V1_2::OutputShape> returnedOutputShapes; + V1_2::Timing returnedTiming; auto cb = [&returnedStatus, &returnedOutputShapes, &returnedTiming]( - V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, - const Timing& timing) { + V1_0::ErrorStatus status, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { returnedStatus = status; returnedOutputShapes = outputShapes; returnedTiming = timing; }; // execute - const Return<void> ret = mpPreparedModel->executeSynchronously(fullRequest, measure, cb); + const hardware::Return<void> ret = + mpPreparedModel->executeSynchronously(fullRequest, measure, cb); if (!ret.isOk() || returnedStatus != V1_0::ErrorStatus::NONE) { LOG(ERROR) << "IPreparedModelAdapter::execute -- Error executing"; return {returnedStatus, std::move(returnedOutputShapes), kNoTiming}; @@ -103,14 +103,15 @@ class DefaultBurstExecutorWithCache : public ExecutionBurstServer::IBurstExecuto private: V1_2::IPreparedModel* const mpPreparedModel; - std::map<int32_t, hidl_memory> mMemoryCache; + std::map<int32_t, hardware::hidl_memory> mMemoryCache; }; } // anonymous namespace // serialize result std::vector<FmqResultDatum> serialize(V1_0::ErrorStatus errorStatus, - const std::vector<OutputShape>& outputShapes, Timing timing) { + const std::vector<V1_2::OutputShape>& outputShapes, + V1_2::Timing timing) { // count how many elements need to be sent for a request size_t count = 2 + outputShapes.size(); for (const auto& outputShape : outputShapes) { @@ -161,7 +162,7 @@ std::vector<FmqResultDatum> serialize(V1_0::ErrorStatus errorStatus, } // deserialize request -std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, MeasureTiming>> deserialize( +std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>> deserialize( const std::vector<FmqRequestDatum>& data) { using discriminator = FmqRequestDatum::hidl_discriminator; @@ -188,7 +189,7 @@ std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, MeasureTiming>> de } // unpackage input operands - std::vector<RequestArgument> inputs; + std::vector<V1_0::RequestArgument> inputs; inputs.reserve(numberOfInputOperands); for (size_t operand = 0; operand < numberOfInputOperands; ++operand) { // validate input operand information @@ -202,7 +203,7 @@ std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, MeasureTiming>> de data[index].inputOperandInformation(); index++; const bool hasNoValue = operandInfo.hasNoValue; - const DataLocation location = operandInfo.location; + const V1_0::DataLocation location = operandInfo.location; const uint32_t numberOfDimensions = operandInfo.numberOfDimensions; // unpackage operand dimensions @@ -229,7 +230,7 @@ std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, MeasureTiming>> de } // unpackage output operands - std::vector<RequestArgument> outputs; + std::vector<V1_0::RequestArgument> outputs; outputs.reserve(numberOfOutputOperands); for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) { // validate output operand information @@ -243,7 +244,7 @@ std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, MeasureTiming>> de data[index].outputOperandInformation(); index++; const bool hasNoValue = operandInfo.hasNoValue; - const DataLocation location = operandInfo.location; + const V1_0::DataLocation location = operandInfo.location; const uint32_t numberOfDimensions = operandInfo.numberOfDimensions; // unpackage operand dimensions @@ -294,7 +295,7 @@ std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, MeasureTiming>> de } // unpackage measureTiming - const MeasureTiming measure = data[index].measureTiming(); + const V1_2::MeasureTiming measure = data[index].measureTiming(); index++; // validate packet information @@ -333,7 +334,7 @@ RequestChannelReceiver::RequestChannelReceiver(std::unique_ptr<FmqRequestChannel std::chrono::microseconds pollingTimeWindow) : mFmqRequestChannel(std::move(fmqRequestChannel)), kPollingTimeWindow(pollingTimeWindow) {} -std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, MeasureTiming>> +std::optional<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>> RequestChannelReceiver::getBlocking() { const auto packet = getPacketBlocking(); if (!packet) { @@ -463,7 +464,8 @@ ResultChannelSender::ResultChannelSender(std::unique_ptr<FmqResultChannel> fmqRe : mFmqResultChannel(std::move(fmqResultChannel)) {} bool ResultChannelSender::send(V1_0::ErrorStatus errorStatus, - const std::vector<OutputShape>& outputShapes, Timing timing) { + const std::vector<V1_2::OutputShape>& outputShapes, + V1_2::Timing timing) { const std::vector<FmqResultDatum> serialized = serialize(errorStatus, outputShapes, timing); return sendPacket(serialized); } @@ -555,10 +557,10 @@ ExecutionBurstServer::~ExecutionBurstServer() { mWorker.join(); } -Return<void> ExecutionBurstServer::freeMemory(int32_t slot) { +hardware::Return<void> ExecutionBurstServer::freeMemory(int32_t slot) { std::lock_guard<std::mutex> hold(mMutex); mExecutorWithCache->removeCacheEntry(slot); - return Void(); + return hardware::Void(); } void ExecutionBurstServer::ensureCacheEntriesArePresentLocked(const std::vector<int32_t>& slots) { @@ -580,14 +582,15 @@ void ExecutionBurstServer::ensureCacheEntriesArePresentLocked(const std::vector< } V1_0::ErrorStatus errorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; - std::vector<hidl_memory> returnedMemories; - auto cb = [&errorStatus, &returnedMemories](V1_0::ErrorStatus status, - const hidl_vec<hidl_memory>& memories) { + std::vector<hardware::hidl_memory> returnedMemories; + auto cb = [&errorStatus, &returnedMemories]( + V1_0::ErrorStatus status, + const hardware::hidl_vec<hardware::hidl_memory>& memories) { errorStatus = status; returnedMemories = memories; }; - const Return<void> ret = mCallback->getMemories(unknownSlots, cb); + const hardware::Return<void> ret = mCallback->getMemories(unknownSlots, cb); if (!ret.isOk() || errorStatus != V1_0::ErrorStatus::NONE || returnedMemories.size() != unknownSlots.size()) { diff --git a/nn/common/GraphDump.cpp b/nn/common/GraphDump.cpp index 3c208cd88..146e1c6cb 100644 --- a/nn/common/GraphDump.cpp +++ b/nn/common/GraphDump.cpp @@ -18,9 +18,8 @@ #include "GraphDump.h" -#include "HalInterfaces.h" - #include <android-base/logging.h> + #include <algorithm> #include <iostream> #include <map> @@ -28,11 +27,11 @@ #include <string> #include <utility> +#include "Utils.h" + namespace android { namespace nn { -using namespace hal; - // class Dumper is a wrapper around an std::ostream (if instantiated // with a pointer to a stream) or around LOG(INFO) (otherwise). // @@ -112,25 +111,40 @@ static std::string translate(OperandType type) { return "OEM"; case OperandType::TENSOR_OEM_BYTE: return "TOEMB"; - default: - return toString(type); + default: { + std::ostringstream oss; + oss << type; + return oss.str(); + } } } // If the specified Operand of the specified Model has OperandType // nnType corresponding to C++ type cppType and is of -// OperandLifeTime::CONSTANT_COPY, then write the Operand's value to +// Operand::LifeTime::CONSTANT_COPY, then write the Operand's value to // the Dumper. namespace { template <OperandType nnType, typename cppType> void tryValueDump(Dumper& dump, const Model& model, const Operand& opnd) { - if (opnd.type != nnType || opnd.lifetime != OperandLifeTime::CONSTANT_COPY || - opnd.location.length != sizeof(cppType)) { + if (opnd.type != nnType) { + return; + } + + const void* pointer = nullptr; + if (opnd.lifetime == Operand::LifeTime::CONSTANT_COPY) { + pointer = model.operandValues.data() + opnd.location.offset; + } else if (opnd.lifetime == Operand::LifeTime::POINTER) { + pointer = std::get<const void*>(opnd.location.pointer); + } else { + return; + } + + if (opnd.location.length != sizeof(cppType)) { return; } cppType val; - memcpy(&val, &model.operandValues[opnd.location.offset], sizeof(cppType)); + memcpy(&val, pointer, sizeof(cppType)); dump << " = " << val; } } // namespace @@ -172,25 +186,28 @@ void graphDump(const char* name, const Model& model, std::ostream* outStream) { const char* kind = nullptr; const char* io = nullptr; switch (opnd.lifetime) { - case OperandLifeTime::CONSTANT_COPY: + case Operand::LifeTime::CONSTANT_COPY: kind = "COPY"; break; - case OperandLifeTime::CONSTANT_REFERENCE: + case Operand::LifeTime::CONSTANT_REFERENCE: kind = "REF"; break; - case OperandLifeTime::SUBGRAPH_INPUT: + case Operand::LifeTime::SUBGRAPH_INPUT: io = "input"; break; - case OperandLifeTime::SUBGRAPH_OUTPUT: + case Operand::LifeTime::SUBGRAPH_OUTPUT: io = "output"; break; - case OperandLifeTime::NO_VALUE: + case Operand::LifeTime::NO_VALUE: kind = "NO"; break; - case OperandLifeTime::SUBGRAPH: + case Operand::LifeTime::SUBGRAPH: kind = "SUBGRAPH"; break; - default: + case Operand::LifeTime::POINTER: + kind = "POINTER"; + break; + case Operand::LifeTime::TEMPORARY_VARIABLE: // nothing interesting break; } @@ -205,7 +222,7 @@ void graphDump(const char* name, const Model& model, std::ostream* outStream) { tryValueDump<OperandType::FLOAT32, float>(dump, model, opnd); tryValueDump<OperandType::INT32, int>(dump, model, opnd); tryValueDump<OperandType::UINT32, unsigned>(dump, model, opnd); - if (opnd.dimensions.size()) { + if (!opnd.dimensions.empty()) { dump << "("; for (unsigned i = 0, e = opnd.dimensions.size(); i < e; i++) { if (i > 0) { @@ -230,7 +247,7 @@ void graphDump(const char* name, const Model& model, std::ostream* outStream) { dump << " ordering=out"; } } - dump << " label=\"" << i << ": " << toString(operation.type) << "\"]" << Dumper::endl; + dump << " label=\"" << i << ": " << operation.type << "\"]" << Dumper::endl; { // operation inputs for (unsigned in = 0, inE = operation.inputs.size(); in < inE; in++) { diff --git a/nn/common/MetaModel.cpp b/nn/common/MetaModel.cpp index 30d88a181..81d12829d 100644 --- a/nn/common/MetaModel.cpp +++ b/nn/common/MetaModel.cpp @@ -24,6 +24,7 @@ #include <sstream> #include <type_traits> #include <utility> +#include <vector> #include "GraphDump.h" #include "HalInterfaces.h" @@ -31,14 +32,12 @@ namespace android::nn { -using namespace hal; - namespace { // Add an element to the end of the vector and return a pair consisting of the // index of the new element and a pointer to the new element. template <class T> -std::pair<uint32_t, T*> extend(hidl_vec<T>* vec) { +std::pair<uint32_t, T*> extend(hardware::hidl_vec<T>* vec) { size_t nextIndex = vec->size(); vec->resize(nextIndex + 1); return {nextIndex, &(*vec)[nextIndex]}; @@ -48,14 +47,14 @@ std::pair<uint32_t, T*> extend(hidl_vec<T>* vec) { // return a pair consisting of the index of the new element and a pointer to the // new element. template <class T> -std::pair<uint32_t, T*> extend(hidl_vec<T>* vec, const T& val) { +std::pair<uint32_t, T*> extend(hardware::hidl_vec<T>* vec, const T& val) { auto extended = extend(vec); *extended.second = val; return extended; } template <typename T> -bool operator<(const hidl_vec<T>& a, const hidl_vec<T>& b) { +bool operator<(const hardware::hidl_vec<T>& a, const hardware::hidl_vec<T>& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); } @@ -63,19 +62,19 @@ bool operator<(const hidl_vec<T>& a, const hidl_vec<T>& b) { template <class T_Model> struct ModelVersion; template <> -struct ModelVersion<hal::V1_0::Model> { +struct ModelVersion<V1_0::Model> { static constexpr char name[] = "V1_0"; }; template <> -struct ModelVersion<hal::V1_1::Model> { +struct ModelVersion<V1_1::Model> { static constexpr char name[] = "V1_1"; }; template <> -struct ModelVersion<hal::V1_2::Model> { +struct ModelVersion<V1_2::Model> { static constexpr char name[] = "V1_2"; }; template <> -struct ModelVersion<hal::V1_3::Model> { +struct ModelVersion<V1_3::Model> { static constexpr char name[] = "V1_3"; }; @@ -84,16 +83,16 @@ struct ModelVersion<hal::V1_3::Model> { template <typename T_ReturnType> T_ReturnType uncheckedConvertTo(OperationType type); template <> -hal::V1_0::OperationType uncheckedConvertTo<hal::V1_0::OperationType>(OperationType type) { - return uncheckedConvertToV1_0(type); +V1_0::OperationType uncheckedConvertTo<V1_0::OperationType>(OperationType type) { + return uncheckedConvertToV1_0(convertToV1_3(type)); } template <> -hal::V1_1::OperationType uncheckedConvertTo<hal::V1_1::OperationType>(OperationType type) { - return uncheckedConvertToV1_1(type); +V1_1::OperationType uncheckedConvertTo<V1_1::OperationType>(OperationType type) { + return uncheckedConvertToV1_1(convertToV1_3(type)); } template <> -hal::V1_2::OperationType uncheckedConvertTo<hal::V1_2::OperationType>(OperationType type) { - return uncheckedConvertToV1_2(type); +V1_2::OperationType uncheckedConvertTo<V1_2::OperationType>(OperationType type) { + return uncheckedConvertToV1_2(convertToV1_3(type)); } // Dispatcher mechanism for calling an appropriate convertToV1_* given the @@ -101,45 +100,41 @@ hal::V1_2::OperationType uncheckedConvertTo<hal::V1_2::OperationType>(OperationT template <typename T_ReturnType> T_ReturnType convertTo(Operand operand); template <> -hal::V1_0::Operand convertTo<hal::V1_0::Operand>(Operand operand) { - return convertToV1_0(operand); +V1_0::Operand convertTo<V1_0::Operand>(Operand operand) { + return convertToV1_0(convertToV1_3(operand)); } template <> -hal::V1_2::Operand convertTo<hal::V1_2::Operand>(Operand operand) { - return convertToV1_2(operand); +V1_2::Operand convertTo<V1_2::Operand>(Operand operand) { + return convertToV1_2(convertToV1_3(operand)); } // Dispatcher mechanism for calling an appropriate convertToV1_* given the -// desired return type. Note that there are no V1_[12]::OperandLifeTime types. +// desired return type. Note that there are no V1_[12]::Operand::LifeTime types. template <typename T_ReturnType> -T_ReturnType convertTo(OperandLifeTime lifetime); +T_ReturnType convertTo(V1_3::OperandLifeTime lifetime); template <> -hal::V1_0::OperandLifeTime convertTo<hal::V1_0::OperandLifeTime>(OperandLifeTime lifetime) { +V1_0::OperandLifeTime convertTo<V1_0::OperandLifeTime>(V1_3::OperandLifeTime lifetime) { return convertToV1_0(lifetime); } -template <> -hal::V1_3::OperandLifeTime convertTo<hal::V1_3::OperandLifeTime>(OperandLifeTime lifetime) { - return lifetime; -} // Dispatcher mechanism for calling an appropriate compliantWithV1_* given the // desired target model type. template <typename T_SlicedModel> -void getNoncompliantOperations(const hal::V1_3::Model& model, +void getNoncompliantOperations(const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations); template <> -void getNoncompliantOperations<hal::V1_0::Model>(const hal::V1_3::Model& model, - std::set<uint32_t>* noncompliantOperations) { +void getNoncompliantOperations<V1_0::Model>(const V1_3::Model& model, + std::set<uint32_t>* noncompliantOperations) { compliantWithV1_0(model, noncompliantOperations); } template <> -void getNoncompliantOperations<hal::V1_1::Model>(const hal::V1_3::Model& model, - std::set<uint32_t>* noncompliantOperations) { +void getNoncompliantOperations<V1_1::Model>(const V1_3::Model& model, + std::set<uint32_t>* noncompliantOperations) { compliantWithV1_1(model, noncompliantOperations); } template <> -void getNoncompliantOperations<hal::V1_2::Model>(const hal::V1_3::Model& model, - std::set<uint32_t>* noncompliantOperations) { +void getNoncompliantOperations<V1_2::Model>(const V1_3::Model& model, + std::set<uint32_t>* noncompliantOperations) { compliantWithV1_2(model, noncompliantOperations); } @@ -191,18 +186,25 @@ MetaModel::ReturnedSlice<T_SlicedModel> MetaModel::getSlice(Slice<T_SlicedModel> return slice->mSlicedOperationIndexToOrigIndex.at(slicedOperationIndex); }))); } -template MetaModel::ReturnedSlice<hal::V1_0::Model> MetaModel::getSlice( - Slice<hal::V1_0::Model>* slice) const; -template MetaModel::ReturnedSlice<hal::V1_1::Model> MetaModel::getSlice( - Slice<hal::V1_1::Model>* slice) const; -template MetaModel::ReturnedSlice<hal::V1_2::Model> MetaModel::getSlice( - Slice<hal::V1_2::Model>* slice) const; -// When adding HAL version 1.4, make sure to handle control flow and referenced -// subgraphs here properly. A V1_3 sliced model should contain an IF/WHILE and -// its referenced subgraphs only if there are no V1_4+ operations in those -// subgraphs. -// template MetaModel::ReturnedSlice<hal::V1_3::Model> MetaModel::getSlice( -// Slice<hal::V1_3::Model>* slice) const; +template MetaModel::ReturnedSlice<V1_0::Model> MetaModel::getSlice(Slice<V1_0::Model>* slice) const; +template MetaModel::ReturnedSlice<V1_1::Model> MetaModel::getSlice(Slice<V1_1::Model>* slice) const; +template MetaModel::ReturnedSlice<V1_2::Model> MetaModel::getSlice(Slice<V1_2::Model>* slice) const; +template <> +MetaModel::ReturnedSlice<V1_3::Model> MetaModel::getSlice(Slice<V1_3::Model>* slice) const { + CHECK(slice != nullptr); + if (slice->mState == SliceState::UNINITIALIZED) { + // When adding HAL version 1.4, make sure to handle control flow and referenced + // subgraphs here properly. A V1_3 sliced model should contain an IF/WHILE and + // its referenced subgraphs only if there are no V1_4+ operations in those + // subgraphs. + *slice = { + .mState = SliceState::NORMAL, + .mHidlModel = convertToV1_3(mModel), + }; + } + Mapper trivialMapper = [](uint32_t i) { return i; }; + return std::make_pair(slice->mHidlModel, trivialMapper); +} // Utility class for makeSlice(). // @@ -234,8 +236,8 @@ template MetaModel::ReturnedSlice<hal::V1_2::Model> MetaModel::getSlice( template <typename T_SlicedOperand> class MetaModel::OrigOperandToSlicedInputOperandIndex { public: - OrigOperandToSlicedInputOperandIndex(hidl_vec<T_SlicedOperand>* slicedOperands, - hidl_vec<uint32_t>* slicedInputIndexes) + OrigOperandToSlicedInputOperandIndex(hardware::hidl_vec<T_SlicedOperand>* slicedOperands, + hardware::hidl_vec<uint32_t>* slicedInputIndexes) : mSlicedOperands(*slicedOperands), mSlicedInputIndexes(*slicedInputIndexes) {} // Given an operand from the original model, return the index of the @@ -246,21 +248,19 @@ class MetaModel::OrigOperandToSlicedInputOperandIndex { auto it = mMap.find(operand); if (it != mMap.end()) { VLOG(COMPILATION) << "OrigOperandToSlicedInputOperandIndex::getIndex looked for " - << toString(operand) << " and found " << it->second << ": " - << toString(it->first); + << operand << " and found " << it->second << ": " << it->first; return it->second; } // Create - operand.numberOfConsumers = 0; - operand.lifetime = convertTo<decltype(operand.lifetime)>(OperandLifeTime::SUBGRAPH_INPUT); + operand.lifetime = Operand::LifeTime::SUBGRAPH_INPUT; operand.location = {}; uint32_t slicedOperandIndex = extend(&mSlicedOperands, convertTo<T_SlicedOperand>(operand)).first; mMap[operand] = slicedOperandIndex; extend(&mSlicedInputIndexes, slicedOperandIndex); VLOG(COMPILATION) << "OrigOperandToSlicedInputOperandIndex::getIndex created " - << slicedOperandIndex << ": " << toString(operand); + << slicedOperandIndex << ": " << operand; return slicedOperandIndex; } @@ -284,38 +284,36 @@ class MetaModel::OrigOperandToSlicedInputOperandIndex { } private: - static bool compare(const SymmPerChannelQuantParams& a, - const SymmPerChannelQuantParams& b) { + static bool compare(const Operand::SymmPerChannelQuantParams& a, + const Operand::SymmPerChannelQuantParams& b) { if (a.scales != b.scales) { return a.scales < b.scales; } return a.channelDim < b.channelDim; } - static bool compare(const OperandExtraParams& a, const OperandExtraParams& b) { - if (a.getDiscriminator() != b.getDiscriminator()) { - return a.getDiscriminator() < b.getDiscriminator(); + static bool compare(const Operand::ExtraParams& a, const Operand::ExtraParams& b) { + if (a.index() != b.index()) { + return a.index() < b.index(); } - - switch (a.getDiscriminator()) { - case OperandExtraParams::hidl_discriminator::channelQuant: - return compare(a.channelQuant(), b.channelQuant()); - - case OperandExtraParams::hidl_discriminator::extension: - return a.extension() < b.extension(); - - case OperandExtraParams::hidl_discriminator::none: - return false; - - default: - CHECK(false) << "Unexpected"; - return false; + if (std::holds_alternative<Operand::SymmPerChannelQuantParams>(a)) { + return compare(std::get<Operand::SymmPerChannelQuantParams>(a), + std::get<Operand::SymmPerChannelQuantParams>(b)); } + if (std::holds_alternative<Operand::ExtensionParams>(a)) { + return compare(std::get<Operand::ExtensionParams>(a), + std::get<Operand::ExtensionParams>(b)); + } + if (std::holds_alternative<Operand::NoParams>(a)) { + return false; + } + CHECK(false) << "Unexpected"; + return false; } }; std::map<Operand, uint32_t, Compare> mMap; - hidl_vec<T_SlicedOperand>& mSlicedOperands; - hidl_vec<uint32_t>& mSlicedInputIndexes; + hardware::hidl_vec<T_SlicedOperand>& mSlicedOperands; + hardware::hidl_vec<uint32_t>& mSlicedInputIndexes; }; template <class T_SlicedModel> @@ -329,11 +327,14 @@ void MetaModel::processOperations( using SlicedOperation = typename Slice<T_SlicedModel>::Operation; using SlicedOperationType = typename Slice<T_SlicedModel>::OperationType; - const auto& origOperands = mHidlModel.main.operands; - const auto& origOperations = mHidlModel.main.operations; + const auto& origOperands = mModel.main.operands; + const auto& origOperations = mModel.main.operations; auto& slicedOperands = slice->mHidlModel.operands; auto& slicedOperations = slice->mHidlModel.operations; + std::vector<uint32_t> origOperandNumberOfConsumers = + countNumberOfConsumers(origOperands.size(), origOperations); + for (uint32_t origOperationIndex = 0; origOperationIndex < origOperations.size(); ++origOperationIndex) { const Operation& origOperation = origOperations[origOperationIndex]; @@ -401,9 +402,9 @@ void MetaModel::processOperations( slicedOperation.outputs[outputNum] = slicedOperandIndex; const auto subgraphOutputLifetime = convertTo<decltype(slicedOperand.lifetime)>( - OperandLifeTime::SUBGRAPH_OUTPUT); + V1_3::OperandLifeTime::SUBGRAPH_OUTPUT); if (!inputOperandIndexesOfCompliantOperations.count(origOperandIndex) && - origOperand.numberOfConsumers) { + origOperandNumberOfConsumers[origOperandIndex] != 0) { // Was consumed only by noncompliant operations; convert to // an output of the sliced model. slicedOperand.lifetime = subgraphOutputLifetime; @@ -427,24 +428,24 @@ MetaModel::Slice<T_SlicedModel> MetaModel::makeSlice() const { Slice<T_SlicedModel> slice; - const auto& origOperands = mHidlModel.main.operands; - const auto& origOperations = mHidlModel.main.operations; + const auto& origOperands = mModel.main.operands; + const auto& origOperations = mModel.main.operations; auto& slicedOperands = slice.mHidlModel.operands; // Indexes of elements of noncompliant origOperations std::set<uint32_t> noncompliantOperations; - getNoncompliantOperations<T_SlicedModel>(mHidlModel, &noncompliantOperations); + getNoncompliantOperations<T_SlicedModel>(convertToV1_3(mModel), &noncompliantOperations); // Map from an operand index in origOperands to the corresponding operand index in // slicedOperands std::map<uint32_t, uint32_t> origOperandIndexToSlicedIndex; // Collect the operand indexes of every operand that is an input to a - // compliant operation. If the operand is a CONSTANT_* or a NO_VALUE, copy - // it to the sliced model and update origOperandIndexToSlicedIndex - // accordingly. Otherwise, we'll deal with the operand in the subsequent - // "Main loop", where we process operation outputs (intermediates and model - // outputs). + // compliant operation. If the operand is a CONSTANT_*, POINTER, or a + // NO_VALUE, copy it to the sliced model and update + // origOperandIndexToSlicedIndex accordingly. Otherwise, we'll deal with + // the operand in the subsequent "Main loop", where we process operation + // outputs (intermediates and model outputs). std::set<uint32_t> inputOperandIndexesOfCompliantOperations; for (uint32_t origOperationIndex = 0; origOperationIndex < origOperations.size(); ++origOperationIndex) { @@ -455,9 +456,10 @@ MetaModel::Slice<T_SlicedModel> MetaModel::makeSlice() const { if (inputOperandIndexesOfCompliantOperations.insert(input).second) { const Operand& origOperand = origOperands[input]; switch (origOperand.lifetime) { - case OperandLifeTime::CONSTANT_COPY: - case OperandLifeTime::CONSTANT_REFERENCE: - case OperandLifeTime::NO_VALUE: { + case Operand::LifeTime::CONSTANT_COPY: + case Operand::LifeTime::CONSTANT_REFERENCE: + case Operand::LifeTime::POINTER: + case Operand::LifeTime::NO_VALUE: { const uint32_t slicedOperandIndex = extend(&slicedOperands, convertTo<SlicedOperand>(origOperand)) .first; @@ -482,7 +484,7 @@ MetaModel::Slice<T_SlicedModel> MetaModel::makeSlice() const { // only if it is consumed by at least one compliant operation. Note that in // the sliced model we share all model inputs of the same "type"; and that // we may later add model inputs to the sliced model. - for (uint32_t origInputIndex : mHidlModel.main.inputIndexes) { + for (uint32_t origInputIndex : mModel.main.inputIndexes) { if (inputOperandIndexesOfCompliantOperations.count(origInputIndex)) { const uint32_t slicedIndex = origOperandToSlicedInputOperandIndex.getIndex(origOperands[origInputIndex]); @@ -502,19 +504,19 @@ MetaModel::Slice<T_SlicedModel> MetaModel::makeSlice() const { // This would be more complex and probably take more computation time, but // it would reduce the size of the sliced model, and hence the time spent // copying it around and passing it across the HAL interface. - slice.mHidlModel.operandValues = mHidlModel.operandValues; - slice.mHidlModel.pools = mHidlModel.pools; + slice.mHidlModel.operandValues = convertToV1_0(mModel.operandValues); + slice.mHidlModel.pools = convertToV1_0(mModel.pools); if (VLOG_IS_ON(COMPILATION)) { { std::ostringstream fromName; - fromName << "Slice: From " << ModelVersion<decltype(mHidlModel)>::name; - graphDump(fromName.str().c_str(), mHidlModel); + fromName << "Slice: From canonical"; + graphDump(fromName.str().c_str(), mModel); } { std::ostringstream toName; toName << "Slice: To " << ModelVersion<decltype(slice.mHidlModel)>::name; - graphDump(toName.str().c_str(), convertToV1_3(slice.mHidlModel)); + graphDump(toName.str().c_str(), uncheckedConvert(convertToV1_3(slice.mHidlModel))); } } diff --git a/nn/common/OperationResolver.cpp b/nn/common/OperationResolver.cpp index fce3af4cc..e6792b2a6 100644 --- a/nn/common/OperationResolver.cpp +++ b/nn/common/OperationResolver.cpp @@ -23,8 +23,6 @@ namespace android { namespace nn { -using namespace hal; - // TODO(b/119608412): Find a way to not reference every operation here. const OperationRegistration* register_ABS(); const OperationRegistration* register_ADD(); diff --git a/nn/common/OperationsUtils.cpp b/nn/common/OperationsUtils.cpp index f0bcb0ed7..9f2af2269 100644 --- a/nn/common/OperationsUtils.cpp +++ b/nn/common/OperationsUtils.cpp @@ -32,8 +32,6 @@ namespace nn { namespace { -using namespace hal; - bool validateOperandTypes(const std::vector<OperandType>& expectedTypes, const char* tag, uint32_t operandCount, std::function<OperandType(uint32_t)> getOperandType) { @@ -41,8 +39,8 @@ bool validateOperandTypes(const std::vector<OperandType>& expectedTypes, const c for (uint32_t i = 0; i < operandCount; ++i) { OperandType type = getOperandType(i); NN_RET_CHECK(type == expectedTypes[i]) - << "Invalid " << tag << " tensor type " << toString(type) << " for " << tag << " " - << i << ", expected " << toString(expectedTypes[i]); + << "Invalid " << tag << " tensor type " << type << " for " << tag << " " << i + << ", expected " << expectedTypes[i]; } return true; } @@ -97,17 +95,17 @@ bool validateHalVersion(const IOperationValidationContext* context, if (i != 0) { message << ", "; } - message << toString(context->getInputType(i)); + message << context->getInputType(i); } message << "} and outputs {"; for (uint32_t i = 0, n = context->getNumOutputs(); i < n; ++i) { if (i != 0) { message << ", "; } - message << toString(context->getOutputType(i)); + message << context->getOutputType(i); } - message << "} is only supported since " << toString(minSupportedHalVersion) - << " (validating using " << toString(context->getHalVersion()) << ")"; + message << "} is only supported since " << minSupportedHalVersion << " (validating using " + << context->getHalVersion() << ")"; NN_RET_CHECK_FAIL() << message.str(); } return true; diff --git a/nn/common/Utils.cpp b/nn/common/Utils.cpp index 1c41e5940..398da5508 100644 --- a/nn/common/Utils.cpp +++ b/nn/common/Utils.cpp @@ -22,6 +22,10 @@ #include <android-base/properties.h> #include <android-base/strings.h> #include <errno.h> +#include <nnapi/hal/1.0/Conversions.h> +#include <nnapi/hal/1.1/Conversions.h> +#include <nnapi/hal/1.2/Conversions.h> +#include <nnapi/hal/1.3/Conversions.h> #include <poll.h> #include <algorithm> @@ -42,13 +46,12 @@ #include "NeuralNetworksOEM.h" #include "OperationResolver.h" #include "ValidateHal.h" +#include "nnapi/TypeUtils.h" namespace android { namespace nn { -using namespace hal; - -constexpr PerformanceInfo kNoPerformanceInfo = {.execTime = FLT_MAX, .powerUsage = FLT_MAX}; +constexpr V1_0::PerformanceInfo kNoPerformanceInfo = {.execTime = FLT_MAX, .powerUsage = FLT_MAX}; const char kVLogPropKey[] = "debug.nn.vlog"; int vLogMask = ~0; @@ -98,21 +101,26 @@ void initVLogMask() { } } -Deadline makeDeadline(uint64_t duration) { +TimeoutDuration makeTimeoutDuration(uint64_t nanoseconds) { + // According to the standard, std::chrono::nanoseconds::rep is a signed + // integer type of at least 64 bits. This check prevents an overflow when + // rep is exactly 64 bits. + if constexpr (sizeof(std::chrono::nanoseconds::rep) == sizeof(int64_t)) { + nanoseconds = std::min(nanoseconds, + static_cast<uint64_t>(std::chrono::nanoseconds::max().count())); + } + return std::chrono::nanoseconds{nanoseconds}; +} + +Deadline makeDeadline(TimeoutDuration duration) { const auto maxTime = Deadline::max(); const auto currentTime = std::chrono::steady_clock::now(); - // Create Deadline. If there would be an overflow, use the max value. - const uint64_t remainingNanoseconds = - std::chrono::duration_cast<std::chrono::nanoseconds>(maxTime - currentTime).count(); - if (duration > remainingNanoseconds) { + // If there would be an overflow, use the max value. + if (duration > maxTime - currentTime) { return maxTime; } - return currentTime + std::chrono::nanoseconds{duration}; -} - -std::optional<Deadline> makeDeadline(std::optional<uint64_t> duration) { - return duration.has_value() ? makeDeadline(*duration) : std::optional<Deadline>{}; + return currentTime + duration; } static uint64_t getMaxNanosecondsSinceEpoch() { @@ -121,8 +129,8 @@ static uint64_t getMaxNanosecondsSinceEpoch() { return maxTime.time_since_epoch().count(); } -std::optional<Deadline> makeDeadline(const OptionalTimePoint& timePoint) { - using Discriminator = hal::OptionalTimePoint::hidl_discriminator; +std::optional<Deadline> makeDeadline(const V1_3::OptionalTimePoint& timePoint) { + using Discriminator = V1_3::OptionalTimePoint::hidl_discriminator; if (timePoint.getDiscriminator() == Discriminator::none) { return std::nullopt; } @@ -146,12 +154,7 @@ bool hasDeadlinePassed(const std::optional<Deadline>& deadline) { } static OptionalTimePoint makeTimePoint(const Deadline& deadline) { - const auto timeSinceEpoch = deadline.time_since_epoch(); - const uint64_t nanosecondsSinceEpoch = - std::chrono::duration_cast<std::chrono::nanoseconds>(timeSinceEpoch).count(); - OptionalTimePoint ret; - ret.nanosecondsSinceEpoch(nanosecondsSinceEpoch); - return ret; + return deadline; } OptionalTimePoint makeTimePoint(const std::optional<Deadline>& deadline) { @@ -159,18 +162,18 @@ OptionalTimePoint makeTimePoint(const std::optional<Deadline>& deadline) { } static bool isExtensionOperandType(int32_t type) { - return static_cast<uint32_t>(type) > static_cast<uint32_t>(OperandTypeRange::BASE_MAX); + return (static_cast<uint32_t>(type) >> kExtensionTypeBits) != 0; } static bool isExtensionOperationType(ANeuralNetworksOperationType type) { - return static_cast<uint32_t>(type) > static_cast<uint32_t>(OperationTypeRange::BASE_MAX); + return (static_cast<uint32_t>(type) >> kExtensionTypeBits) != 0; } -bool isExtensionOperandType(OperandType type) { +bool isExtensionOperandType(V1_3::OperandType type) { return isExtensionOperandType(static_cast<int32_t>(type)); } -bool isExtensionOperationType(OperationType type) { +bool isExtensionOperationType(V1_3::OperationType type) { return isExtensionOperationType(static_cast<int32_t>(type)); } @@ -211,7 +214,7 @@ class OperationValidationContext : public IOperationValidationContext { uint32_t getNumInputs() const override; OperandType getInputType(uint32_t index) const override; Shape getInputShape(uint32_t index) const override; - const OperandExtraParams getInputExtraParams(uint32_t index) const override; + const Operand::ExtraParams& getInputExtraParams(uint32_t index) const override; uint32_t getNumOutputs() const override; OperandType getOutputType(uint32_t index) const override; @@ -266,7 +269,7 @@ Shape OperationValidationContext::getInputShape(uint32_t index) const { operand->extraParams}; } -const OperandExtraParams OperationValidationContext::getInputExtraParams(uint32_t index) const { +const Operand::ExtraParams& OperationValidationContext::getInputExtraParams(uint32_t index) const { return getInputOperand(index)->extraParams; } @@ -284,15 +287,11 @@ Shape OperationValidationContext::getOutputShape(uint32_t index) const { #define COUNT(X) (sizeof(X) / sizeof(X[0])) -std::string getOperandTypeName(OperandType type) { +std::string getOperandTypeName(V1_3::OperandType type) { return toString(type); } -static std::string getOperationName(uint32_t code) { - return getOperationName(static_cast<OperationType>(code)); -} - -std::string getOperationName(OperationType type) { +std::string getOperationName(V1_3::OperationType type) { return toString(type); } @@ -360,12 +359,14 @@ bool nonExtensionOperandTypeIsScalar(int type) { } uint32_t nonExtensionOperandSizeOfData(OperandType type, const std::vector<uint32_t>& dimensions) { - CHECK(!isExtensionOperandType(type)) << "Size of extension operand data is unknown"; - int n = static_cast<int>(type); - uint32_t sizeOfElement = tableLookup(kSizeOfDataType, kSizeOfDataTypeOEM, n); - return tableLookup(kScalarDataType, kScalarDataTypeOEM, n) - ? sizeOfElement - : sizeOfTensorData(sizeOfElement, dimensions); + const size_t size = getNonExtensionSize(type, dimensions).value(); + CHECK_LE(size, std::numeric_limits<uint32_t>::max()); + return size; +} + +uint32_t nonExtensionOperandSizeOfData(V1_3::OperandType type, + const std::vector<uint32_t>& dimensions) { + return nonExtensionOperandSizeOfData(uncheckedConvert(type), dimensions); } // Returns a pair of {false, size} on success, {true, 0} if size overflows uint32_t. @@ -389,9 +390,9 @@ uint32_t sizeOfTensorData(uint32_t sizeOfElement, const std::vector<uint32_t>& d return size; } -bool nonExtensionOperandSizeOfDataOverflowsUInt32(hal::OperandType type, +bool nonExtensionOperandSizeOfDataOverflowsUInt32(OperandType type, const std::vector<uint32_t>& dimensions) { - CHECK(!isExtensionOperandType(type)) << "Size of extension operand data is unknown"; + CHECK(!isExtension(type)) << "Size of extension operand data is unknown"; int n = static_cast<int>(type); uint32_t sizeOfElement = tableLookup(kSizeOfDataType, kSizeOfDataTypeOEM, n); return tableLookup(kScalarDataType, kScalarDataTypeOEM, n) @@ -399,6 +400,11 @@ bool nonExtensionOperandSizeOfDataOverflowsUInt32(hal::OperandType type, : sizeOfTensorDataOverflowsUInt32(sizeOfElement, dimensions); } +bool nonExtensionOperandSizeOfDataOverflowsUInt32(V1_3::OperandType type, + const std::vector<uint32_t>& dimensions) { + return nonExtensionOperandSizeOfDataOverflowsUInt32(uncheckedConvert(type), dimensions); +} + bool sizeOfTensorDataOverflowsUInt32(uint32_t sizeOfElement, const std::vector<uint32_t>& dimensions) { return sizeOfTensorDataHelper(sizeOfElement, dimensions).first; @@ -417,11 +423,21 @@ bool tensorHasUnspecifiedDimensions(OperandType type, const std::vector<uint32_t dimensions.size()); } +bool tensorHasUnspecifiedDimensions(V1_3::OperandType type, + const std::vector<uint32_t>& dimensions) { + return tensorHasUnspecifiedDimensions(static_cast<int>(type), dimensions.data(), + dimensions.size()); +} + bool tensorHasUnspecifiedDimensions(const ANeuralNetworksOperandType* type) { return tensorHasUnspecifiedDimensions(type->type, type->dimensions, type->dimensionCount); } bool tensorHasUnspecifiedDimensions(const Operand& operand) { + return tensorHasUnspecifiedDimensions(operand.type, operand.dimensions); +} + +bool tensorHasUnspecifiedDimensions(const V1_3::Operand& operand) { return tensorHasUnspecifiedDimensions(static_cast<int>(operand.type), operand.dimensions.data(), operand.dimensions.size()); } @@ -490,10 +506,15 @@ void logModelToInfo(const V1_3::Model& model) { LOG(INFO) << "extensionNameToPrefix" << toString(model.extensionNameToPrefix); } +void logModelToInfo(const Model& model) { + LOG(INFO) << "Model start"; + logModelToInfo(convertToV1_3(model)); +} + bool validateOperandSymmPerChannelQuantParams( - const Operand& halOperand, const ANeuralNetworksSymmPerChannelQuantParams& channelQuant, - const char* tag) { - if (halOperand.type != OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { + const V1_3::Operand& halOperand, + const ANeuralNetworksSymmPerChannelQuantParams& channelQuant, const char* tag) { + if (halOperand.type != V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { return false; } @@ -663,17 +684,15 @@ int validateOperationOperandTypes(const std::vector<Operand>& operands, uint32_t } for (uint32_t i = 0; i < inOperandCount; i++) { if (operands[inOperandIndexes[i]].type != inExpectedTypes[i]) { - LOG(ERROR) << "Invalid input tensor type " - << toString(operands[inOperandIndexes[i]].type) << " for input " << i - << ", expected " << toString(inExpectedTypes[i]); + LOG(ERROR) << "Invalid input tensor type " << operands[inOperandIndexes[i]].type + << " for input " << i << ", expected " << inExpectedTypes[i]; return ANEURALNETWORKS_BAD_DATA; } } for (uint32_t i = 0; i < outOperandCount; i++) { if (operands[outOperandIndexes[i]].type != outExpectedInTypes[i]) { - LOG(ERROR) << "Invalid output tensor type " - << toString(operands[outOperandIndexes[i]].type) << " for input " << i - << ", expected " << toString(outExpectedInTypes[i]); + LOG(ERROR) << "Invalid output tensor type " << operands[outOperandIndexes[i]].type + << " for input " << i << ", expected " << outExpectedInTypes[i]; return ANEURALNETWORKS_BAD_DATA; } } @@ -684,9 +703,9 @@ int validateOperationOperandTypes(const std::vector<Operand>& operands, uint32_t static int validateHalVersion(ANeuralNetworksOperationType opType, HalVersion halVersion, HalVersion minSupportedHalVersion) { if (halVersion < minSupportedHalVersion) { - LOG(ERROR) << "The given inputs and outputs for operation " << getOperationName(opType) - << " are only supported in " << toString(minSupportedHalVersion) - << " and later (validating using " << toString(halVersion) << ")"; + LOG(ERROR) << "The given inputs and outputs for operation " << opType + << " are only supported in " << minSupportedHalVersion + << " and later (validating using " << halVersion << ")"; return ANEURALNETWORKS_BAD_DATA; } return ANEURALNETWORKS_NO_ERROR; @@ -695,7 +714,7 @@ static int validateHalVersion(ANeuralNetworksOperationType opType, HalVersion ha // Checks if two operands have the same types, ranks (if specified), dimensions // (if specified), scales, zeroPoints, and extraParams. static bool compatible(const Operand& a, const Operand& b) { - NN_RET_CHECK(a.type == b.type) << toString(a.type) << " != " << toString(b.type); + NN_RET_CHECK(a.type == b.type) << a.type << " != " << b.type; if (a.dimensions.size() != 0 && b.dimensions.size() != 0) { NN_RET_CHECK_EQ(a.dimensions.size(), b.dimensions.size()) << "Incompatible dimensions"; for (uint32_t i = 0, n = a.dimensions.size(); i < n; ++i) { @@ -706,14 +725,13 @@ static bool compatible(const Operand& a, const Operand& b) { } NN_RET_CHECK_EQ(a.scale, b.scale); NN_RET_CHECK_EQ(a.zeroPoint, b.zeroPoint); - NN_RET_CHECK(a.extraParams == b.extraParams) - << toString(a.extraParams) << " != " << toString(b.extraParams); + NN_RET_CHECK(a.extraParams == b.extraParams) << a.extraParams << " != " << b.extraParams; return true; } static bool validateConditionOperand(const Operand& operand) { NN_RET_CHECK(operand.type == OperandType::TENSOR_BOOL8) - << "Unexpected condition operand type: " << toString(operand.type); + << "Unexpected condition operand type: " << operand.type; NN_RET_CHECK_EQ(operand.dimensions.size(), 1u) << "Condition operand must be a singleton"; NN_RET_CHECK_EQ(operand.dimensions[0], 1u) << "Condition operand must be a singleton"; return true; @@ -764,8 +782,7 @@ static bool validateIfOperation(uint32_t inputCount, const uint32_t* inputs, uin static bool validateControlFlowOperandUnknownSize(const SubgraphValidationHelper& helper, const Operand& operand) { - if (!helper.allowControlFlowOperationWithOperandOfUnknownSize && - !isExtensionOperandType(operand.type)) { + if (!helper.allowControlFlowOperationWithOperandOfUnknownSize && !isExtension(operand.type)) { NN_RET_CHECK_NE(nonExtensionOperandSizeOfData(operand.type, operand.dimensions), 0u); } return true; @@ -847,8 +864,7 @@ static bool validateWhileOperation(uint32_t inputCount, const uint32_t* inputs, static inline int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, const uint32_t* inputIndexes, uint32_t outputCount, const uint32_t* outputIndexes, - const std::vector<hal::Operand>& operands, - HalVersion halVersion) { + const std::vector<Operand>& operands, HalVersion halVersion) { if (opType == ANEURALNETWORKS_IF || opType == ANEURALNETWORKS_WHILE) { NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_3)); LOG(ERROR) << "This validateOperation() overload does not support control flow"; @@ -873,7 +889,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if (halVersion < HalVersion::V1_2) { LOG(ERROR) << "Extension operations are supported since HAL version 1.2, validating using " - << toString(halVersion); + << halVersion; return ANEURALNETWORKS_BAD_DATA; } // There is no other validation we can do for an extension operation. @@ -883,7 +899,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, auto logInvalidInOutNumber = [opType, inputCount, outputCount](int expIn, int expOut) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected " << expIn << ") or output operands (" << outputCount << ", expected " << expOut - << ") for operation " << getOperationName(opType); + << ") for operation " << opType; }; switch (opType) { @@ -916,14 +932,12 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, OperandType::TENSOR_INT32}; outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM_SIGNED}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } const auto inputRank = operands[inputIndexes[0]].dimensions.size(); if (inputRank > 4) { - LOG(ERROR) << "Unsupported input tensor rank for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor rank for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } return validateOperationOperandTypes(operands, inputCount, inputIndexes, @@ -934,7 +948,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if ((inputCount != 3 && inputCount != 2) || outputCount != 1) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 3 or 2) or output operands (" << outputCount - << ", expected 1) for operation " << getOperationName(opType); + << ", expected 1) for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } auto inputType = operands[inputIndexes[0]].type; @@ -957,8 +971,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM_SIGNED, OperandType::INT32}; outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM_SIGNED}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputCount == 3) { @@ -975,7 +988,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if ((inputCount != 3 && inputCount != 2) || outputCount != 1) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 3 or 2) or output operands (" << outputCount - << ", expected 1) for operation " << getOperationName(opType); + << ", expected 1) for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } auto inputType = operands[inputIndexes[0]].type; @@ -998,8 +1011,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM_SIGNED, OperandType::INT32}; outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM_SIGNED}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputCount == 3) { @@ -1023,8 +1035,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inputType != OperandType::TENSOR_INT32 && inputType != OperandType::TENSOR_QUANT8_ASYMM && inputType != OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32, inputType}; @@ -1051,8 +1062,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if (inputType != OperandType::TENSOR_FLOAT32 && inputType != OperandType::TENSOR_INT32 && inputType != OperandType::TENSOR_QUANT8_ASYMM) { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32, @@ -1074,8 +1084,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inputType != OperandType::TENSOR_FLOAT32 && inputType != OperandType::TENSOR_INT32 && inputType != OperandType::TENSOR_QUANT8_ASYMM) { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } auto hashType = operands[inputIndexes[0]].type; @@ -1097,8 +1106,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, OperandType::INT32, }; } else { - LOG(ERROR) << "Unsupported hash tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported hash tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_INT32}; @@ -1117,7 +1125,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, outputCount != kNumOutputsMergedWithState)) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 61) or output operands (" << outputCount - << ", expected 1, 2, 5 or 6) for operation " << getOperationName(opType); + << ", expected 1, 2, 5 or 6) for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } @@ -1125,8 +1133,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, auto inputType = operands[inputIndexes[0]].type; if (inputType != OperandType::TENSOR_FLOAT32 && inputType != OperandType::TENSOR_FLOAT16) { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } @@ -1162,7 +1169,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if ((inputCount != 23 && inputCount != 27) || outputCount != 4) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 23 or 27) or output operands (" << outputCount - << ", expected 4) for operation " << getOperationName(opType); + << ", expected 4) for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } std::vector<OperandType> inExpectedTypes; @@ -1170,8 +1177,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, auto inputType = operands[inputIndexes[0]].type; if (inputType != OperandType::TENSOR_FLOAT32 && inputType != OperandType::TENSOR_FLOAT16) { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } @@ -1239,8 +1245,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, OperandType::TENSOR_INT32, }; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_INT32}; @@ -1279,8 +1284,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, OperandType::TENSOR_FLOAT16, }; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } return validateOperationOperandTypes(operands, inputCount, inputIndexes, @@ -1299,8 +1303,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, } else if (inputType == OperandType::TENSOR_FLOAT16) { NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2)); } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } std::vector<OperandType> inExpectedTypes = { @@ -1316,7 +1319,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if ((inputCount != 3 && inputCount != 2) || outputCount != 1) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 3 or 2) or output operands (" << outputCount - << ", expected 1) for operation " << getOperationName(opType); + << ", expected 1) for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } auto inputType = operands[inputIndexes[0]].type; @@ -1349,8 +1352,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, }; outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM_SIGNED}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputCount == 3) { @@ -1367,7 +1369,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if ((inputCount != 4 && inputCount != 3) || outputCount != 1) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 4 or 3) or output operands (" << outputCount - << ", expected 1) for operation " << getOperationName(opType); + << ", expected 1) for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } auto inputType = operands[inputIndexes[0]].type; @@ -1407,8 +1409,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, }; outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM_SIGNED}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputCount == 4) { @@ -1462,14 +1463,12 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, }; outExpectedTypes = {inputType}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } const auto inputRank = operands[inputIndexes[0]].dimensions.size(); if (inputRank > 4) { - LOG(ERROR) << "Unsupported input tensor rank for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor rank for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } return validateOperationOperandTypes(operands, inputCount, inputIndexes, @@ -1514,14 +1513,12 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, }; // TODO(b/116699425): Make it UINT8. outExpectedTypes = {inputType}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } const auto inputRank = operands[inputIndexes[0]].dimensions.size(); if (inputRank > 4) { - LOG(ERROR) << "Unsupported input tensor rank for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor rank for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } return validateOperationOperandTypes(operands, inputCount, inputIndexes, @@ -1559,7 +1556,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, outExpectedTypes = {inputType}; // Only identity CAST is supported. NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_3)); } else { - LOG(ERROR) << "Unsupported data type for operation " << getOperationName(opType); + LOG(ERROR) << "Unsupported data type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } // Validate that output shape is equal to input shape if dimensions @@ -1586,8 +1583,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, } const auto inputRank = operands[inputIndexes[0]].dimensions.size(); if (inputRank > 4) { - LOG(ERROR) << "Unsupported input tensor rank for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor rank for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } auto inputType = operands[inputIndexes[0]].type; @@ -1600,8 +1596,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_3)); } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } std::vector<OperandType> inExpectedTypes = {inputType, OperandType::TENSOR_INT32, @@ -1628,8 +1623,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inExpectedTypes = {inputType, OperandType::INT32}; outExpectedTypes = {OperandType::TENSOR_INT32}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2)); @@ -1653,8 +1647,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inExpectedTypes = {inputType, OperandType::INT32}; outExpectedTypes = {inputType}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { @@ -1669,7 +1662,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, case ANEURALNETWORKS_SPLIT: { if (inputCount != 3) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 3)" - << getOperationName(opType); + << opType; return ANEURALNETWORKS_BAD_DATA; } auto inputType = operands[inputIndexes[0]].type; @@ -1678,8 +1671,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inputType != OperandType::TENSOR_INT32 && inputType != OperandType::TENSOR_QUANT8_ASYMM && inputType != OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { @@ -1711,8 +1703,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inExpectedTypes = {inputType, inputType}; outExpectedTypes = {inputType}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { @@ -1728,7 +1719,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, if ((inputCount != 12 && inputCount != 9) || outputCount != 1) { LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 12 or 9) or output operands (" << outputCount - << ", expected 1) for operation " << getOperationName(opType); + << ", expected 1) for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } auto inputType = operands[inputIndexes[0]].type; @@ -1751,15 +1742,16 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { if (filterType != inputType && filterType != OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { - LOG(ERROR) << "Unsupported filter tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported filter tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (filterType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL && - operands[inputIndexes[1]].extraParams.channelQuant().channelDim != 0) { + std::get<Operand::SymmPerChannelQuantParams>( + operands[inputIndexes[1]].extraParams) + .channelDim != 0) { LOG(ERROR) << "Unsupported filter tensor channel dimension for operation " - << getOperationName(opType); + << opType; return ANEURALNETWORKS_BAD_DATA; } @@ -1769,8 +1761,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, OperandType::INT32, OperandType::INT32}; outExpectedTypes = {inputType}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } @@ -1805,8 +1796,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inExpectedTypes = {inputType, OperandType::TENSOR_INT32}; outExpectedTypes = {inputType}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { @@ -1831,8 +1821,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, inExpectedTypes = {inputType, inputType}; outExpectedTypes = {inputType}; } else { - LOG(ERROR) << "Unsupported input tensor type for operation " - << getOperationName(opType); + LOG(ERROR) << "Unsupported input tensor type for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { @@ -1864,7 +1853,7 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, static_cast<OperationType>(opType)); if (operationRegistration == nullptr) { if (0 <= opType && opType < kNumberOfOperationTypes) { - LOG(ERROR) << getOperationName(opType) << " not registered"; + LOG(ERROR) << opType << " not registered"; } else { LOG(ERROR) << "Operation type " << opType << " out of the range [0, " << kNumberOfOperationTypes << ")"; @@ -1872,14 +1861,14 @@ int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, return ANEURALNETWORKS_UNEXPECTED_NULL; } if (operationRegistration->validate == nullptr) { - LOG(ERROR) << "Incomplete operation registration: " << getOperationName(opType); + LOG(ERROR) << "Incomplete operation registration: " << opType; return ANEURALNETWORKS_UNEXPECTED_NULL; } OperationValidationContext context(operationRegistration->name, inputCount, inputIndexes, outputCount, outputIndexes, operands.data(), halVersion); if (!operationRegistration->validate(&context)) { - LOG(ERROR) << "Validation failed for operation " << getOperationName(opType); + LOG(ERROR) << "Validation failed for operation " << opType; return ANEURALNETWORKS_BAD_DATA; } return ANEURALNETWORKS_NO_ERROR; @@ -1943,12 +1932,28 @@ int convertErrorStatusToResultCode(ErrorStatus status) { return ANEURALNETWORKS_RESOURCE_EXHAUSTED_TRANSIENT; case ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT: return ANEURALNETWORKS_RESOURCE_EXHAUSTED_PERSISTENT; + case ErrorStatus::DEAD_OBJECT: + return ANEURALNETWORKS_DEAD_OBJECT; } - LOG(ERROR) << "Unknown ErrorStatus " << toString(status) - << " mapped to ANEURALNETWORKS_OP_FAILED"; + LOG(ERROR) << "Unknown ErrorStatus " << status << " mapped to ANEURALNETWORKS_OP_FAILED"; return ANEURALNETWORKS_OP_FAILED; } +V1_3::ErrorStatus convertResultCodeToHalErrorStatus(int resultCode) { + return convertToV1_3(convertResultCodeToErrorStatus(resultCode)); +} + +int convertErrorStatusToResultCode(V1_3::ErrorStatus status) { + return convertErrorStatusToResultCode(uncheckedConvert(status)); +} + +std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult( + V1_3::ErrorStatus status, const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { + return getExecutionResult(uncheckedConvert(status), uncheckedConvert(outputShapes), + uncheckedConvert(timing)); +} + std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult( ErrorStatus status, std::vector<OutputShape> outputShapes, Timing timing) { constexpr Timing kNoTiming = {std::numeric_limits<uint64_t>::max(), @@ -1966,42 +1971,22 @@ std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult( return {n, std::move(outputShapes), timing}; } -std::optional<std::vector<uint32_t>> combineDimensions(const std::vector<uint32_t>& lhs, - const std::vector<uint32_t>& rhs) { - if (rhs.empty()) return lhs; - if (lhs.empty()) return rhs; - if (lhs.size() != rhs.size()) { - LOG(ERROR) << "Incompatible ranks: " << toString(lhs) << " and " << toString(rhs); - return std::nullopt; - } - std::vector<uint32_t> combined = lhs; - for (uint32_t i = 0; i < lhs.size(); i++) { - if (lhs[i] == 0) { - combined[i] = rhs[i]; - } else if (rhs[i] != 0 && lhs[i] != rhs[i]) { - LOG(ERROR) << "Incompatible dimensions: " << toString(lhs) << " and " << toString(rhs); - return std::nullopt; - } - } - return combined; -} - // Capabilities::operandPerformance utilities. // The field Capabilities::operandPerformance is a vector sorted by the field // Capabilities::OperandPerformance::type. template <HalVersion version> -hidl_vec<VersionedOperandPerformance<version>> nonExtensionOperandPerformance( - PerformanceInfo perf) { +hardware::hidl_vec<VersionedOperandPerformance<version>> nonExtensionOperandPerformance( + V1_0::PerformanceInfo perf) { using OpPerf = VersionedOperandPerformance<version>; // Note: range presents enumerators in declaration order, not in numerical order. - static constexpr hidl_enum_range<VersionedOperandType<version>> kOperandTypeRange; + static constexpr hardware::hidl_enum_range<VersionedOperandType<version>> kOperandTypeRange; std::vector<OpPerf> ret; ret.reserve(kOperandTypeRange.end() - kOperandTypeRange.begin()); for (VersionedOperandType<version> type : kOperandTypeRange) { - if (static_cast<OperandType>(type) != OperandType::SUBGRAPH) { + if (static_cast<V1_3::OperandType>(type) != V1_3::OperandType::SUBGRAPH) { ret.push_back(OpPerf{type, perf}); } } @@ -2011,14 +1996,14 @@ hidl_vec<VersionedOperandPerformance<version>> nonExtensionOperandPerformance( return ret; } -template hal::hidl_vec<V1_2::Capabilities::OperandPerformance> -nonExtensionOperandPerformance<HalVersion::V1_2>(PerformanceInfo perf); -template hal::hidl_vec<V1_3::Capabilities::OperandPerformance> -nonExtensionOperandPerformance<HalVersion::V1_3>(PerformanceInfo perf); +template hardware::hidl_vec<V1_2::Capabilities::OperandPerformance> +nonExtensionOperandPerformance<HalVersion::V1_2>(V1_0::PerformanceInfo perf); +template hardware::hidl_vec<V1_3::Capabilities::OperandPerformance> +nonExtensionOperandPerformance<HalVersion::V1_3>(V1_0::PerformanceInfo perf); template <HalVersion version> -void update(hal::hidl_vec<VersionedOperandPerformance<version>>* operandPerformance, - VersionedOperandType<version> type, hal::PerformanceInfo perf) { +void update(hardware::hidl_vec<VersionedOperandPerformance<version>>* operandPerformance, + VersionedOperandType<version> type, V1_0::PerformanceInfo perf) { CHECK(operandPerformance != nullptr); const auto it = std::lower_bound(operandPerformance->begin(), operandPerformance->end(), type, @@ -2029,23 +2014,24 @@ void update(hal::hidl_vec<VersionedOperandPerformance<version>>* operandPerforma it->info = perf; } -void update(hidl_vec<V1_2::Capabilities::OperandPerformance>* operandPerformance, - V1_2::OperandType type, PerformanceInfo perf) { +void update(hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>* operandPerformance, + V1_2::OperandType type, V1_0::PerformanceInfo perf) { update<HalVersion::V1_2>(operandPerformance, type, perf); } -void update(hidl_vec<V1_3::Capabilities::OperandPerformance>* operandPerformance, - V1_3::OperandType type, PerformanceInfo perf) { +void update(hardware::hidl_vec<V1_3::Capabilities::OperandPerformance>* operandPerformance, + V1_3::OperandType type, V1_0::PerformanceInfo perf) { update<HalVersion::V1_3>(operandPerformance, type, perf); } template <HalVersion version> -PerformanceInfo lookup(const hidl_vec<VersionedOperandPerformance<version>>& operandPerformance, - VersionedOperandType<version> type) { +V1_0::PerformanceInfo lookup( + const hardware::hidl_vec<VersionedOperandPerformance<version>>& operandPerformance, + VersionedOperandType<version> type) { const auto it = std::lower_bound(operandPerformance.begin(), operandPerformance.end(), type, [](const VersionedOperandPerformance<version>& perf, VersionedOperandType<version> type) { - return static_cast<OperandType>(perf.type) < - static_cast<OperandType>(type); + return static_cast<V1_3::OperandType>(perf.type) < + static_cast<V1_3::OperandType>(type); }); if (it == operandPerformance.end()) { LOG(WARNING) << "No PerformanceInfo for " << toString(type); @@ -2055,12 +2041,14 @@ PerformanceInfo lookup(const hidl_vec<VersionedOperandPerformance<version>>& ope } } -PerformanceInfo lookup(const hidl_vec<V1_2::Capabilities::OperandPerformance>& operandPerformance, - V1_2::OperandType type) { +V1_0::PerformanceInfo lookup( + const hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>& operandPerformance, + V1_2::OperandType type) { return lookup<HalVersion::V1_2>(operandPerformance, type); } -PerformanceInfo lookup(const hidl_vec<V1_3::Capabilities::OperandPerformance>& operandPerformance, - V1_3::OperandType type) { +V1_0::PerformanceInfo lookup( + const hardware::hidl_vec<V1_3::Capabilities::OperandPerformance>& operandPerformance, + V1_3::OperandType type) { CHECK(type != V1_3::OperandType::SUBGRAPH) << "Use Capabilities::ifPerformance or Capabilities::whilePerformance"; return lookup<HalVersion::V1_3>(operandPerformance, type); @@ -2070,16 +2058,16 @@ PerformanceInfo lookup(const hidl_vec<V1_3::Capabilities::OperandPerformance>& o // In Android P, most data types are treated as having the same performance as TENSOR_QUANT8_ASYMM. // This array must be in sorted order. -static const OperandType kQuantized8PerformanceConsistentWithP[] = { - OperandType::INT32, OperandType::UINT32, OperandType::TENSOR_INT32, OperandType::OEM, - OperandType::TENSOR_OEM_BYTE}; +static const V1_3::OperandType kQuantized8PerformanceConsistentWithP[] = { + V1_3::OperandType::INT32, V1_3::OperandType::UINT32, V1_3::OperandType::TENSOR_INT32, + V1_3::OperandType::OEM, V1_3::OperandType::TENSOR_OEM_BYTE}; static bool isQuantized8PerformanceConsistentWithP(const V1_2::Capabilities& capabilities) { - const PerformanceInfo quantized8Performance = + const V1_0::PerformanceInfo quantized8Performance = lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_QUANT8_ASYMM); return std::all_of(std::begin(kQuantized8PerformanceConsistentWithP), std::end(kQuantized8PerformanceConsistentWithP), - [quantized8Performance, &capabilities](OperandType type) { + [quantized8Performance, &capabilities](V1_3::OperandType type) { return quantized8Performance == lookup(capabilities.operandPerformance, static_cast<V1_2::OperandType>(type)); @@ -2087,26 +2075,26 @@ static bool isQuantized8PerformanceConsistentWithP(const V1_2::Capabilities& cap } static bool isQuantized8PerformanceConsistentWithP(const V1_3::Capabilities& capabilities) { - const PerformanceInfo quantized8Performance = - lookup(capabilities.operandPerformance, OperandType::TENSOR_QUANT8_ASYMM); + const V1_0::PerformanceInfo quantized8Performance = + lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_ASYMM); return std::all_of(std::begin(kQuantized8PerformanceConsistentWithP), std::end(kQuantized8PerformanceConsistentWithP), - [quantized8Performance, &capabilities](OperandType type) { + [quantized8Performance, &capabilities](V1_3::OperandType type) { return quantized8Performance == lookup(capabilities.operandPerformance, type); }); } -static hidl_vec<V1_2::Capabilities::OperandPerformance> makeQuantized8PerformanceConsistentWithP( - PerformanceInfo quantized8Performance) { - hidl_vec<V1_2::Capabilities::OperandPerformance> ret( +static hardware::hidl_vec<V1_2::Capabilities::OperandPerformance> +makeQuantized8PerformanceConsistentWithP(V1_0::PerformanceInfo quantized8Performance) { + hardware::hidl_vec<V1_2::Capabilities::OperandPerformance> ret( std::size(kQuantized8PerformanceConsistentWithP)); - std::transform( - std::begin(kQuantized8PerformanceConsistentWithP), - std::end(kQuantized8PerformanceConsistentWithP), ret.begin(), - [quantized8Performance](OperandType type) -> V1_2::Capabilities::OperandPerformance { - return {static_cast<V1_2::OperandType>(type), quantized8Performance}; - }); + std::transform(std::begin(kQuantized8PerformanceConsistentWithP), + std::end(kQuantized8PerformanceConsistentWithP), ret.begin(), + [quantized8Performance]( + V1_3::OperandType type) -> V1_2::Capabilities::OperandPerformance { + return {static_cast<V1_2::OperandType>(type), quantized8Performance}; + }); return ret; } @@ -2119,9 +2107,9 @@ bool compliantWithV1_0(const V1_1::Capabilities& capabilities) { } bool compliantWithV1_0(const V1_2::Capabilities& capabilities) { - const PerformanceInfo perfTensorFloat32 = + const V1_0::PerformanceInfo perfTensorFloat32 = lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_FLOAT32); - const PerformanceInfo perfFloat32 = + const V1_0::PerformanceInfo perfFloat32 = lookup(capabilities.operandPerformance, V1_2::OperandType::FLOAT32); if (perfTensorFloat32 != perfFloat32 || perfTensorFloat32 != capabilities.relaxedFloat32toFloat16PerformanceTensor || @@ -2133,10 +2121,10 @@ bool compliantWithV1_0(const V1_2::Capabilities& capabilities) { } bool compliantWithV1_0(const V1_3::Capabilities& capabilities) { - const PerformanceInfo perfTensorFloat32 = - lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32); - const PerformanceInfo perfFloat32 = - lookup(capabilities.operandPerformance, OperandType::FLOAT32); + const V1_0::PerformanceInfo perfTensorFloat32 = + lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32); + const V1_0::PerformanceInfo perfFloat32 = + lookup(capabilities.operandPerformance, V1_3::OperandType::FLOAT32); if (perfTensorFloat32 != perfFloat32 || perfTensorFloat32 != capabilities.relaxedFloat32toFloat16PerformanceTensor || perfFloat32 != capabilities.relaxedFloat32toFloat16PerformanceScalar) { @@ -2168,8 +2156,8 @@ bool compliantWithV1_1(const V1_2::Capabilities& capabilities) { bool compliantWithV1_1(const V1_3::Capabilities& capabilities) { if ((capabilities.relaxedFloat32toFloat16PerformanceTensor != capabilities.relaxedFloat32toFloat16PerformanceScalar) || - (lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32) != - lookup(capabilities.operandPerformance, OperandType::FLOAT32))) { + (lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32) != + lookup(capabilities.operandPerformance, V1_3::OperandType::FLOAT32))) { return false; } @@ -2323,9 +2311,9 @@ V1_0::Capabilities convertToV1_0(const V1_3::Capabilities& capabilities) { << " from V1_3::Capabilities to V1_0::Capabilities"; } return {.float32Performance = - lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32), - .quantized8Performance = - lookup(capabilities.operandPerformance, OperandType::TENSOR_QUANT8_ASYMM)}; + lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32), + .quantized8Performance = lookup(capabilities.operandPerformance, + V1_3::OperandType::TENSOR_QUANT8_ASYMM)}; } V1_1::Capabilities convertToV1_1(const V1_0::Capabilities& capabilities) { @@ -2357,9 +2345,9 @@ V1_1::Capabilities convertToV1_1(const V1_3::Capabilities& capabilities) { << " from V1_3::Capabilities to V1_1::Capabilities"; } return {.float32Performance = - lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32), + lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32), .quantized8Performance = - lookup(capabilities.operandPerformance, OperandType::TENSOR_QUANT8_ASYMM), + lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_ASYMM), .relaxedFloat32toFloat16Performance = capabilities.relaxedFloat32toFloat16PerformanceTensor}; } @@ -2415,7 +2403,7 @@ V1_2::Capabilities convertToV1_2(const V1_3::Capabilities& capabilities) { capabilities.relaxedFloat32toFloat16PerformanceTensor, }; const auto& inputOpPerf = capabilities.operandPerformance; - hidl_vec<V1_3::Capabilities::OperandPerformance> opPerfSupported; + hardware::hidl_vec<V1_3::Capabilities::OperandPerformance> opPerfSupported; opPerfSupported.resize(inputOpPerf.size()); auto last = std::copy_if(inputOpPerf.begin(), inputOpPerf.end(), opPerfSupported.begin(), @@ -2477,17 +2465,18 @@ static V1_1::Operation convertToV1_1(const V1_0::Operation& operation) { .outputs = operation.outputs}; } -static hidl_vec<V1_0::Operation> uncheckedConvertToV1_0( - const hidl_vec<V1_1::Operation>& operations) { - hidl_vec<V1_0::Operation> result(operations.size()); +static hardware::hidl_vec<V1_0::Operation> uncheckedConvertToV1_0( + const hardware::hidl_vec<V1_1::Operation>& operations) { + hardware::hidl_vec<V1_0::Operation> result(operations.size()); std::transform( operations.begin(), operations.end(), result.begin(), [](const V1_1::Operation& operation) { return uncheckedConvertToV1_0(operation); }); return result; } -static hidl_vec<V1_1::Operation> convertToV1_1(const hidl_vec<V1_0::Operation>& operations) { - hidl_vec<V1_1::Operation> result(operations.size()); +static hardware::hidl_vec<V1_1::Operation> convertToV1_1( + const hardware::hidl_vec<V1_0::Operation>& operations) { + hardware::hidl_vec<V1_1::Operation> result(operations.size()); std::transform(operations.begin(), operations.end(), result.begin(), [](const V1_0::Operation& operation) { return convertToV1_1(operation); }); return result; @@ -2513,13 +2502,15 @@ static bool compliantWith(HalVersion version, const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations) { // A boolean vector indicating whether each pool is compliant with the target HAL version. std::vector<bool> isPoolCompliant(model.pools.size(), false); - std::transform(model.pools.begin(), model.pools.end(), isPoolCompliant.begin(), - [version](const hidl_memory& pool) { return validatePool(pool, version); }); + std::transform( + model.pools.begin(), model.pools.end(), isPoolCompliant.begin(), + [version](const hardware::hidl_memory& pool) { return validatePool(pool, version); }); // A boolean vector indicating whether each operand is compliant with the target HAL version. std::vector<bool> isOperandCompliant(model.main.operands.size(), false); std::transform(model.main.operands.begin(), model.main.operands.end(), - isOperandCompliant.begin(), [&isPoolCompliant, version](const Operand& op) { + isOperandCompliant.begin(), + [&isPoolCompliant, version](const V1_3::Operand& op) { bool is_operand_compliant = false; switch (version) { case HalVersion::UNKNOWN: @@ -2541,22 +2532,24 @@ static bool compliantWith(HalVersion version, const V1_3::Model& model, break; } return is_operand_compliant && - !(op.lifetime == OperandLifeTime::CONSTANT_REFERENCE && + !(op.lifetime == V1_3::OperandLifeTime::CONSTANT_REFERENCE && !isPoolCompliant[op.location.poolIndex]); }); - auto allOperandsCompliant = [&isOperandCompliant](const hidl_vec<uint32_t>& indices) { + auto allOperandsCompliant = [&isOperandCompliant](const hardware::hidl_vec<uint32_t>& indices) { return std::all_of( indices.begin(), indices.end(), [&isOperandCompliant](const uint32_t ind) { return isOperandCompliant[ind]; }); }; - auto localValidateOperation = [&model, version, &allOperandsCompliant](const Operation& op) { + auto localValidateOperation = [&model, version, + &allOperandsCompliant](const V1_3::Operation& op) { if (!allOperandsCompliant(op.inputs) || !allOperandsCompliant(op.outputs)) return false; - int error = validateOperation( - static_cast<int32_t>(op.type), op.inputs.size(), - op.inputs.size() > 0 ? op.inputs.data() : nullptr, op.outputs.size(), - op.outputs.size() > 0 ? op.outputs.data() : nullptr, model.main.operands, version); + int error = validateOperation(static_cast<int32_t>(op.type), op.inputs.size(), + op.inputs.size() > 0 ? op.inputs.data() : nullptr, + op.outputs.size(), + op.outputs.size() > 0 ? op.outputs.data() : nullptr, + uncheckedConvert(model.main.operands), version); return error == ANEURALNETWORKS_NO_ERROR; }; @@ -2586,15 +2579,17 @@ bool compliantWithV1_0(const V1_1::Model& model) { // V1_0::Model because all 1.0 drivers require strict calculation by default // in the P NN runtime. Even if fp16 calculations are allowed, they can // still be computed by a strict fp32 driver. - return std::all_of( - model.operations.begin(), model.operations.end(), [&model](const V1_1::Operation& op) { - int error = validateOperation(static_cast<int32_t>(op.type), op.inputs.size(), - op.inputs.size() > 0 ? op.inputs.data() : nullptr, - op.outputs.size(), - op.outputs.size() > 0 ? op.outputs.data() : nullptr, - convertToV1_3(model.operands), HalVersion::V1_0); - return error == ANEURALNETWORKS_NO_ERROR; - }); + auto operands = uncheckedConvert(convertToV1_3(model.operands)); + return std::all_of(model.operations.begin(), model.operations.end(), + [&operands](const V1_1::Operation& op) { + int error = validateOperation( + static_cast<int32_t>(op.type), op.inputs.size(), + op.inputs.size() > 0 ? op.inputs.data() : nullptr, + op.outputs.size(), + op.outputs.size() > 0 ? op.outputs.data() : nullptr, operands, + HalVersion::V1_0); + return error == ANEURALNETWORKS_NO_ERROR; + }); } bool compliantWithV1_0(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations) { @@ -2697,81 +2692,86 @@ static V1_3::Operation convertToV1_3(const V1_2::Operation& operation) { .outputs = operation.outputs}; } -static hidl_vec<V1_0::Operation> uncheckedConvertToV1_0( - const hidl_vec<V1_3::Operation>& operations) { - hidl_vec<V1_0::Operation> result(operations.size()); +static hardware::hidl_vec<V1_0::Operation> uncheckedConvertToV1_0( + const hardware::hidl_vec<V1_3::Operation>& operations) { + hardware::hidl_vec<V1_0::Operation> result(operations.size()); std::transform( operations.begin(), operations.end(), result.begin(), [](const V1_3::Operation& operation) { return uncheckedConvertToV1_0(operation); }); return result; } -static hidl_vec<V1_0::Operation> uncheckedConvertToV1_0( - const hidl_vec<V1_2::Operation>& operations) { - hidl_vec<V1_0::Operation> result(operations.size()); +static hardware::hidl_vec<V1_0::Operation> uncheckedConvertToV1_0( + const hardware::hidl_vec<V1_2::Operation>& operations) { + hardware::hidl_vec<V1_0::Operation> result(operations.size()); std::transform( operations.begin(), operations.end(), result.begin(), [](const V1_2::Operation& operation) { return uncheckedConvertToV1_0(operation); }); return result; } -static hidl_vec<V1_2::Operation> uncheckedConvertToV1_2( - const hidl_vec<V1_3::Operation>& operations) { - hidl_vec<V1_2::Operation> result(operations.size()); +static hardware::hidl_vec<V1_2::Operation> uncheckedConvertToV1_2( + const hardware::hidl_vec<V1_3::Operation>& operations) { + hardware::hidl_vec<V1_2::Operation> result(operations.size()); std::transform( operations.begin(), operations.end(), result.begin(), [](const V1_3::Operation& operation) { return uncheckedConvertToV1_2(operation); }); return result; } -static hidl_vec<V1_1::Operation> uncheckedConvertToV1_1( - const hidl_vec<V1_2::Operation>& operations) { - hidl_vec<V1_1::Operation> result(operations.size()); +static hardware::hidl_vec<V1_1::Operation> uncheckedConvertToV1_1( + const hardware::hidl_vec<V1_2::Operation>& operations) { + hardware::hidl_vec<V1_1::Operation> result(operations.size()); std::transform( operations.begin(), operations.end(), result.begin(), [](const V1_2::Operation& operation) { return uncheckedConvertToV1_1(operation); }); return result; } -static hidl_vec<V1_1::Operation> uncheckedConvertToV1_1( - const hidl_vec<V1_3::Operation>& operations) { - hidl_vec<V1_1::Operation> result(operations.size()); +static hardware::hidl_vec<V1_1::Operation> uncheckedConvertToV1_1( + const hardware::hidl_vec<V1_3::Operation>& operations) { + hardware::hidl_vec<V1_1::Operation> result(operations.size()); std::transform( operations.begin(), operations.end(), result.begin(), [](const V1_3::Operation& operation) { return uncheckedConvertToV1_1(operation); }); return result; } -static hidl_vec<V1_2::Operation> convertToV1_2(const hidl_vec<V1_0::Operation>& operations) { - hidl_vec<V1_2::Operation> result(operations.size()); +static hardware::hidl_vec<V1_2::Operation> convertToV1_2( + const hardware::hidl_vec<V1_0::Operation>& operations) { + hardware::hidl_vec<V1_2::Operation> result(operations.size()); std::transform(operations.begin(), operations.end(), result.begin(), [](const V1_0::Operation& operation) { return convertToV1_2(operation); }); return result; } -static hidl_vec<V1_2::Operation> convertToV1_2(const hidl_vec<V1_1::Operation>& operations) { - hidl_vec<V1_2::Operation> result(operations.size()); +static hardware::hidl_vec<V1_2::Operation> convertToV1_2( + const hardware::hidl_vec<V1_1::Operation>& operations) { + hardware::hidl_vec<V1_2::Operation> result(operations.size()); std::transform(operations.begin(), operations.end(), result.begin(), [](const V1_1::Operation& operation) { return convertToV1_2(operation); }); return result; } -static hidl_vec<V1_3::Operation> convertToV1_3(const hidl_vec<V1_0::Operation>& operations) { - hidl_vec<V1_3::Operation> result(operations.size()); +static hardware::hidl_vec<V1_3::Operation> convertToV1_3( + const hardware::hidl_vec<V1_0::Operation>& operations) { + hardware::hidl_vec<V1_3::Operation> result(operations.size()); std::transform(operations.begin(), operations.end(), result.begin(), [](const V1_0::Operation& operation) { return convertToV1_3(operation); }); return result; } -static hidl_vec<V1_3::Operation> convertToV1_3(const hidl_vec<V1_1::Operation>& operations) { - hidl_vec<V1_3::Operation> result(operations.size()); +static hardware::hidl_vec<V1_3::Operation> convertToV1_3( + const hardware::hidl_vec<V1_1::Operation>& operations) { + hardware::hidl_vec<V1_3::Operation> result(operations.size()); std::transform(operations.begin(), operations.end(), result.begin(), [](const V1_1::Operation& operation) { return convertToV1_3(operation); }); return result; } -static hidl_vec<V1_3::Operation> convertToV1_3(const hidl_vec<V1_2::Operation>& operations) { - hidl_vec<V1_3::Operation> result(operations.size()); +static hardware::hidl_vec<V1_3::Operation> convertToV1_3( + const hardware::hidl_vec<V1_2::Operation>& operations) { + hardware::hidl_vec<V1_3::Operation> result(operations.size()); std::transform(operations.begin(), operations.end(), result.begin(), [](const V1_2::Operation& operation) { return convertToV1_3(operation); }); return result; @@ -2817,19 +2817,19 @@ V1_0::OperandType convertToV1_0(const V1_3::OperandType& operandType) { return static_cast<V1_0::OperandType>(operandType); } -bool compliantWithV1_0(hal::V1_0::OperandLifeTime lifetime) { +bool compliantWithV1_0(V1_0::OperandLifeTime lifetime) { return true; } -bool compliantWithV1_0(hal::V1_3::OperandLifeTime lifetime) { +bool compliantWithV1_0(V1_3::OperandLifeTime lifetime) { return lifetime != V1_3::OperandLifeTime::SUBGRAPH; } -bool compliantWithV1_3(hal::V1_0::OperandLifeTime lifetime) { +bool compliantWithV1_3(V1_0::OperandLifeTime lifetime) { return true; } -bool compliantWithV1_3(hal::V1_3::OperandLifeTime lifetime) { +bool compliantWithV1_3(V1_3::OperandLifeTime lifetime) { return true; } @@ -2919,57 +2919,57 @@ V1_3::Operand convertToV1_3(const V1_3::Operand& operand) { return operand; } -hidl_vec<V1_0::Operand> convertToV1_0(const hidl_vec<V1_0::Operand>& operands) { +hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_0::Operand>& operands) { return operands; } -hidl_vec<V1_0::Operand> convertToV1_0(const hidl_vec<V1_2::Operand>& operands) { - hidl_vec<V1_0::Operand> result(operands.size()); +hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_2::Operand>& operands) { + hardware::hidl_vec<V1_0::Operand> result(operands.size()); std::transform(operands.begin(), operands.end(), result.begin(), [](const V1_2::Operand& operand) { return convertToV1_0(operand); }); return result; } -hidl_vec<V1_0::Operand> convertToV1_0(const hidl_vec<V1_3::Operand>& operands) { - hidl_vec<V1_0::Operand> result(operands.size()); +hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_3::Operand>& operands) { + hardware::hidl_vec<V1_0::Operand> result(operands.size()); std::transform(operands.begin(), operands.end(), result.begin(), [](const V1_3::Operand& operand) { return convertToV1_0(operand); }); return result; } -hidl_vec<V1_2::Operand> convertToV1_2(const hidl_vec<V1_0::Operand>& operands) { - hidl_vec<V1_2::Operand> result(operands.size()); +hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_0::Operand>& operands) { + hardware::hidl_vec<V1_2::Operand> result(operands.size()); std::transform(operands.begin(), operands.end(), result.begin(), [](const V1_0::Operand& operand) { return convertToV1_2(operand); }); return result; } -hidl_vec<V1_2::Operand> convertToV1_2(const hidl_vec<V1_2::Operand>& operands) { +hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_2::Operand>& operands) { return operands; } -hidl_vec<V1_2::Operand> convertToV1_2(const hidl_vec<V1_3::Operand>& operands) { - hidl_vec<V1_2::Operand> result(operands.size()); +hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_3::Operand>& operands) { + hardware::hidl_vec<V1_2::Operand> result(operands.size()); std::transform(operands.begin(), operands.end(), result.begin(), [](const V1_3::Operand& operand) { return convertToV1_2(operand); }); return result; } -hidl_vec<V1_3::Operand> convertToV1_3(const hidl_vec<V1_0::Operand>& operands) { - hidl_vec<V1_3::Operand> result(operands.size()); +hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_0::Operand>& operands) { + hardware::hidl_vec<V1_3::Operand> result(operands.size()); std::transform(operands.begin(), operands.end(), result.begin(), [](const V1_0::Operand& operand) { return convertToV1_3(operand); }); return result; } -hidl_vec<V1_3::Operand> convertToV1_3(const hidl_vec<V1_2::Operand>& operands) { - hidl_vec<V1_3::Operand> result(operands.size()); +hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_2::Operand>& operands) { + hardware::hidl_vec<V1_3::Operand> result(operands.size()); std::transform(operands.begin(), operands.end(), result.begin(), [](const V1_2::Operand& operand) { return convertToV1_3(operand); }); return result; } -hidl_vec<V1_3::Operand> convertToV1_3(const hidl_vec<V1_3::Operand>& operands) { +hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_3::Operand>& operands) { return operands; } @@ -3158,16 +3158,16 @@ bool compliantWithV1_2(const V1_3::Request& request) { }); } -static hidl_memory convertToV1_0(const V1_3::Request::MemoryPool& pool) { +static hardware::hidl_memory convertToV1_0(const V1_3::Request::MemoryPool& pool) { switch (pool.getDiscriminator()) { case V1_3::Request::MemoryPool::hidl_discriminator::hidlMemory: return pool.hidlMemory(); case V1_3::Request::MemoryPool::hidl_discriminator::token: - return hidl_memory{}; + return hardware::hidl_memory{}; } } -static V1_3::Request::MemoryPool convertToV1_3(const hidl_memory& pool) { +static V1_3::Request::MemoryPool convertToV1_3(const hardware::hidl_memory& pool) { V1_3::Request::MemoryPool ret; ret.hidlMemory(pool); return ret; @@ -3178,7 +3178,7 @@ V1_0::Request convertToV1_0(const V1_0::Request& request) { } static V1_0::Request uncheckedConvertToV1_0(const V1_3::Request& request) { - hidl_vec<hidl_memory> pools(request.pools.size()); + hardware::hidl_vec<hardware::hidl_memory> pools(request.pools.size()); std::transform(request.pools.begin(), request.pools.end(), pools.begin(), [](const auto& pool) { return convertToV1_0(pool); }); return {.inputs = request.inputs, .outputs = request.outputs, .pools = std::move(pools)}; @@ -3201,7 +3201,7 @@ V1_0::Request convertToV1_2(const V1_3::Request& request) { } V1_3::Request convertToV1_3(const V1_0::Request& request) { - hidl_vec<V1_3::Request::MemoryPool> pools(request.pools.size()); + hardware::hidl_vec<V1_3::Request::MemoryPool> pools(request.pools.size()); std::transform(request.pools.begin(), request.pools.end(), pools.begin(), [](const auto& pool) { return convertToV1_3(pool); }); return {.inputs = request.inputs, .outputs = request.outputs, .pools = std::move(pools)}; @@ -3257,5 +3257,293 @@ uint32_t getProp(const char* str, uint32_t defaultValue) { } #endif // NN_DEBUGGABLE +ErrorStatus uncheckedConvert(V1_0::ErrorStatus status) { + return nnTryGetValue(convert(status)); +} + +ErrorStatus uncheckedConvert(V1_3::ErrorStatus status) { + return nnTryGetValue(convert(status)); +} + +OperandType uncheckedConvert(V1_3::OperandType operandType) { + return nnTryGetValue(convert(operandType)); +} + +OperationType uncheckedConvert(V1_3::OperationType operandType) { + return nnTryGetValue(convert(operandType)); +} + +Operand::LifeTime uncheckedConvert(V1_3::OperandLifeTime lifetime) { + return nnTryGetValue(convert(lifetime)); +} + +MeasureTiming uncheckedConvert(V1_2::MeasureTiming measure) { + return nnTryGetValue(convert(measure)); +} + +DataLocation uncheckedConvert(const V1_0::DataLocation& location) { + return nnTryGetValue(convert(location)); +} + +Operand uncheckedConvert(const V1_3::Operand& operand) { + return nnTryGetValue(convert(operand)); +} + +Operand::ExtraParams uncheckedConvert(const V1_2::Operand::ExtraParams& params) { + return nnTryGetValue(convert(params)); +} + +Operand::SymmPerChannelQuantParams uncheckedConvert(const V1_2::SymmPerChannelQuantParams& params) { + return nnTryGetValue(convert(params)); +} + +Operand::ExtensionParams uncheckedConvert(const hardware::hidl_vec<uint8_t>& params) { + return params; +} + +Operation uncheckedConvert(const V1_3::Operation& operation) { + return nnTryGetValue(convert(operation)); +} + +template <typename CanonicalType, typename HalType> +static std::vector<CanonicalType> convertVec(const hardware::hidl_vec<HalType>& items) { + std::vector<CanonicalType> result(items.size()); + std::transform(items.begin(), items.end(), result.begin(), + [](const HalType& item) { return uncheckedConvert(item); }); + return result; +} + +Model uncheckedConvert(const V1_3::Model& model) { + return nnTryGetValue(convert(model)); +} + +Model::Subgraph uncheckedConvert(const V1_3::Subgraph& subgraph) { + return nnTryGetValue(convert(subgraph)); +} + +Model::ExtensionNameAndPrefix uncheckedConvert(const V1_2::Model::ExtensionNameAndPrefix& x) { + return nnTryGetValue(convert(x)); +} + +Request uncheckedConvert(const V1_3::Request& request) { + return nnTryGetValue(convert(request)); +} + +Request::Argument uncheckedConvert(const V1_0::RequestArgument& requestArgument) { + return nnTryGetValue(convert(requestArgument)); +} + +Request::MemoryPool uncheckedConvert(const V1_3::Request::MemoryPool& memoryPool) { + return nnTryGetValue(convert(memoryPool)); +} + +OutputShape uncheckedConvert(const V1_2::OutputShape& outputShape) { + return nnTryGetValue(convert(outputShape)); +} + +std::vector<OutputShape> uncheckedConvert( + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes) { + return convertVec<OutputShape>(outputShapes); +} + +Capabilities uncheckedConvert(const V1_3::Capabilities& capabilities) { + return nnTryGetValue(convert(capabilities)); +} + +Capabilities::OperandPerformance uncheckedConvert( + const V1_3::Capabilities::OperandPerformance& operandPerformance) { + return nnTryGetValue(convert(operandPerformance)); +} + +Capabilities::PerformanceInfo uncheckedConvert(const V1_0::PerformanceInfo& performanceInfo) { + return nnTryGetValue(convert(performanceInfo)); +} + +Extension uncheckedConvert(const V1_2::Extension& extension) { + return nnTryGetValue(convert(extension)); +} + +std::vector<Extension> uncheckedConvert(const hardware::hidl_vec<V1_2::Extension>& extensions) { + return convertVec<Extension>(extensions); +} + +Extension::OperandTypeInformation uncheckedConvert( + const V1_2::Extension::OperandTypeInformation& info) { + return nnTryGetValue(convert(info)); +} + +OptionalTimeoutDuration uncheckedConvert(const V1_3::OptionalTimeoutDuration& timeoutDuration) { + return nnTryGetValue(convert(timeoutDuration)); +} + +Timing uncheckedConvert(const V1_2::Timing& timing) { + return nnTryGetValue(convert(timing)); +} + +V1_0::ErrorStatus convertToV1_0(ErrorStatus status) { + return static_cast<V1_0::ErrorStatus>(static_cast<int>(status)); +} + +V1_3::ErrorStatus convertToV1_3(ErrorStatus status) { + return nnTryGetValue(V1_3::utils::convert(status)); +} + +V1_3::OperandType convertToV1_3(OperandType operandType) { + return nnTryGetValue(V1_3::utils::convert(operandType)); +} + +V1_3::OperationType convertToV1_3(OperationType operandType) { + return nnTryGetValue(V1_3::utils::convert(operandType)); +} + +V1_3::OperandLifeTime convertToV1_3(Operand::LifeTime lifetime) { + return nnTryGetValue(V1_3::utils::convert(lifetime)); +} + +V1_1::ExecutionPreference convertToV1_1(ExecutionPreference preference) { + return nnTryGetValue(V1_1::utils::convert(preference)); +} + +V1_3::Priority convertToV1_3(Priority priority) { + return nnTryGetValue(V1_3::utils::convert(priority)); +} + +V1_2::MeasureTiming convertToV1_2(MeasureTiming measure) { + return nnTryGetValue(V1_2::utils::convert(measure)); +} + +V1_0::DataLocation convertToV1_0(const DataLocation& location) { + return nnTryGetValue(V1_0::utils::convert(location)); +} + +V1_3::Operand convertToV1_3(const Operand& operand) { + return nnTryGetValue(V1_3::utils::convert(operand)); +} + +V1_2::Operand::ExtraParams convertToV1_2(const Operand::ExtraParams& params) { + return nnTryGetValue(V1_2::utils::convert(params)); +} + +V1_2::SymmPerChannelQuantParams convertToV1_2(const Operand::SymmPerChannelQuantParams& params) { + return nnTryGetValue(V1_2::utils::convert(params)); +} + +hardware::hidl_vec<uint8_t> uncheckedConvert(const Operand::ExtensionParams& params) { + return params; +} + +V1_3::Operation convertToV1_3(const Operation& operation) { + return nnTryGetValue(V1_3::utils::convert(operation)); +} + +template <typename HalType, typename CanonicalType> +static hardware::hidl_vec<HalType> convertVecToV1_0(const std::vector<CanonicalType>& items) { + hardware::hidl_vec<HalType> result(items.size()); + std::transform(items.begin(), items.end(), result.begin(), + [](const CanonicalType& item) { return convertToV1_0(item); }); + return result; +} + +template <typename HalType, typename CanonicalType> +static hardware::hidl_vec<HalType> convertVecToV1_2(const std::vector<CanonicalType>& items) { + hardware::hidl_vec<HalType> result(items.size()); + std::transform(items.begin(), items.end(), result.begin(), + [](const CanonicalType& item) { return convertToV1_2(item); }); + return result; +} + +template <typename HalType, typename CanonicalType> +static hardware::hidl_vec<HalType> convertVecToV1_3(const std::vector<CanonicalType>& items) { + hardware::hidl_vec<HalType> result(items.size()); + std::transform(items.begin(), items.end(), result.begin(), + [](const CanonicalType& item) { return convertToV1_3(item); }); + return result; +} + +V1_2::OutputShape convertToV1_2(const OutputShape& outputShape) { + return nnTryGetValue(V1_2::utils::convert(outputShape)); +} + +hardware::hidl_vec<V1_2::OutputShape> convertToV1_2(const std::vector<OutputShape>& outputShapes) { + return convertVecToV1_2<V1_2::OutputShape>(outputShapes); +} + +V1_3::Model convertToV1_3(const Model& model) { + return nnTryGetValue(V1_3::utils::convert(model)); +} + +V1_3::Subgraph convertToV1_3(const Model::Subgraph& subgraph) { + return nnTryGetValue(V1_3::utils::convert(subgraph)); +} + +V1_2::Model::ExtensionNameAndPrefix convertToV1_2(const Model::ExtensionNameAndPrefix& x) { + return nnTryGetValue(V1_2::utils::convert(x)); +} + +V1_3::Request convertToV1_3(const Request& request) { + return nnTryGetValue(V1_3::utils::convert(request)); +} + +V1_0::RequestArgument convertToV1_0(const Request::Argument& requestArgument) { + return nnTryGetValue(V1_0::utils::convert(requestArgument)); +} + +V1_3::Request::MemoryPool convertToV1_3(const Request::MemoryPool& memoryPool) { + return nnTryGetValue(V1_3::utils::convert(memoryPool)); +} + +std::vector<Request::MemoryPool> uncheckedConvert( + const hardware::hidl_vec<V1_3::Request::MemoryPool>& memoryPools) { + return convertVec<Request::MemoryPool>(memoryPools); +} + +V1_3::OptionalTimePoint convertToV1_3(const OptionalTimePoint& timePoint) { + return nnTryGetValue(V1_3::utils::convert(timePoint)); +} + +V1_3::OptionalTimeoutDuration convertToV1_3(const OptionalTimeoutDuration& timeoutDuration) { + return nnTryGetValue(V1_3::utils::convert(timeoutDuration)); +} + +V1_2::Timing convertToV1_2(const Timing& timing) { + return nnTryGetValue(V1_2::utils::convert(timing)); +} + +V1_3::BufferRole convertToV1_3(const BufferRole& bufferRole) { + return nnTryGetValue(V1_3::utils::convert(bufferRole)); +} + +hardware::hidl_vec<V1_3::BufferRole> convertToV1_3(const std::vector<BufferRole>& bufferRoles) { + return convertVecToV1_3<V1_3::BufferRole>(bufferRoles); +} + +hardware::hidl_vec<uint8_t> convertToV1_0(const Model::OperandValues& operandValues) { + return nnTryGetValue(V1_0::utils::convert(operandValues)); +} + +hardware::hidl_memory convertToV1_0(const Memory& memory) { + return nnTryGetValue(V1_0::utils::convert(memory)); +} + +Memory uncheckedConvert(const hardware::hidl_memory& memory) { + return nnTryGetValue(convert(memory)); +} + +hardware::hidl_vec<hardware::hidl_memory> convertToV1_0(const std::vector<Memory>& memories) { + return convertVecToV1_0<hardware::hidl_memory>(memories); +} + +std::vector<Memory> uncheckedConvert(const hardware::hidl_vec<hardware::hidl_memory>& memories) { + return convertVec<Memory>(memories); +} + +std::vector<Model::Subgraph> uncheckedConvert(const hardware::hidl_vec<V1_3::Subgraph>& subgraphs) { + return convertVec<Model::Subgraph>(subgraphs); +} + +std::vector<Operand> uncheckedConvert(const hardware::hidl_vec<V1_3::Operand>& operands) { + return convertVec<Operand>(operands); +} + } // namespace nn } // namespace android diff --git a/nn/common/UtilsTest.cpp b/nn/common/UtilsTest.cpp index 291a7102a..8bc8f2468 100644 --- a/nn/common/UtilsTest.cpp +++ b/nn/common/UtilsTest.cpp @@ -20,16 +20,18 @@ #include <utility> #include <vector> +#include "HalInterfaces.h" #include "MemoryUtils.h" #include "OperationsUtils.cpp" #include "QuantUtils.h" +#include "nnapi/TypeUtils.h" +#include "nnapi/Types.h" namespace android { namespace nn { namespace wrapper { namespace { -using namespace hal; using ::testing::ElementsAreArray; } // namespace @@ -62,9 +64,8 @@ TEST(CalculateBroadcastedShapeTest, FailsOnIncompatible) { } static int32_t getExtensionType(uint16_t extensionPrefix, uint16_t typeWithinExtension) { - constexpr uint8_t kLowBitsType = static_cast<uint8_t>(ExtensionTypeEncoding::LOW_BITS_TYPE); - int32_t type = (extensionPrefix << kLowBitsType) | typeWithinExtension; - EXPECT_TRUE(isExtensionOperandType(static_cast<OperandType>(type))); + int32_t type = (extensionPrefix << kExtensionTypeBits) | typeWithinExtension; + EXPECT_TRUE(isExtensionOperandType(static_cast<V1_3::OperandType>(type))); return type; } @@ -128,7 +129,7 @@ TEST(ValidateOperandTypeTest, TensorSizeDimensionProductOverflow) { } TEST(ValidateRequestTest, UnknownOutputRank) { - Request::MemoryPool pool; + V1_3::Request::MemoryPool pool; pool.hidlMemory(allocateSharedMemory(2 * sizeof(float))); ASSERT_TRUE(pool.hidlMemory().valid()); const V1_3::Model model = { @@ -170,7 +171,7 @@ TEST(ValidateRequestTest, UnknownOutputRank) { } TEST(ValidateRequestTest, ScalarOutput) { - Request::MemoryPool pool; + V1_3::Request::MemoryPool pool; pool.hidlMemory(allocateSharedMemory(sizeof(float) + sizeof(int32_t))); ASSERT_TRUE(pool.hidlMemory().valid()); const V1_3::Model model = { diff --git a/nn/common/ValidateHal.cpp b/nn/common/ValidateHal.cpp index 46f9b2fce..c4e5f96c0 100644 --- a/nn/common/ValidateHal.cpp +++ b/nn/common/ValidateHal.cpp @@ -29,12 +29,11 @@ #include "OperationsUtils.h" #include "Tracing.h" #include "Utils.h" +#include "nnapi/TypeUtils.h" namespace android { namespace nn { -using namespace hal; - template <class T_Model> struct ModelToHalVersion; template <> @@ -56,27 +55,27 @@ struct ModelToHalVersion<V1_3::Model> { class MemoryAccessVerifier { public: - MemoryAccessVerifier(const hidl_vec<hidl_memory>& pools) + MemoryAccessVerifier(const hardware::hidl_vec<hardware::hidl_memory>& pools) : mPoolCount(pools.size()), mPoolSizes(mPoolCount) { for (size_t i = 0; i < mPoolCount; i++) { mPoolSizes[i] = pools[i].size(); } } - MemoryAccessVerifier(const hidl_vec<V1_3::Request::MemoryPool>& pools) + MemoryAccessVerifier(const hardware::hidl_vec<V1_3::Request::MemoryPool>& pools) : mPoolCount(pools.size()), mPoolSizes(mPoolCount) { for (size_t i = 0; i < mPoolCount; i++) { switch (pools[i].getDiscriminator()) { - case Request::MemoryPool::hidl_discriminator::hidlMemory: + case V1_3::Request::MemoryPool::hidl_discriminator::hidlMemory: mPoolSizes[i] = pools[i].hidlMemory().size(); break; - case Request::MemoryPool::hidl_discriminator::token: + case V1_3::Request::MemoryPool::hidl_discriminator::token: // Set size to 0 to enforce length == 0 && offset == 0. mPoolSizes[i] = 0; break; } } } - bool validate(const DataLocation& location) const { + bool validate(const V1_0::DataLocation& location) const { if (location.poolIndex >= mPoolCount) { LOG(ERROR) << "Invalid poolIndex " << location.poolIndex << "/" << mPoolCount; return false; @@ -99,29 +98,29 @@ class MemoryAccessVerifier { static bool validateOperandExtraParams(const V1_3::Operand& operand, uint32_t index) { switch (operand.type) { - case OperandType::FLOAT32: - case OperandType::INT32: - case OperandType::UINT32: - case OperandType::BOOL: - case OperandType::SUBGRAPH: - case OperandType::TENSOR_FLOAT32: - case OperandType::TENSOR_FLOAT16: - case OperandType::TENSOR_INT32: - case OperandType::TENSOR_QUANT8_ASYMM: - case OperandType::TENSOR_QUANT8_ASYMM_SIGNED: - case OperandType::TENSOR_QUANT8_SYMM: - case OperandType::TENSOR_QUANT16_ASYMM: - case OperandType::TENSOR_QUANT16_SYMM: - case OperandType::TENSOR_BOOL8: { + case V1_3::OperandType::FLOAT32: + case V1_3::OperandType::INT32: + case V1_3::OperandType::UINT32: + case V1_3::OperandType::BOOL: + case V1_3::OperandType::SUBGRAPH: + case V1_3::OperandType::TENSOR_FLOAT32: + case V1_3::OperandType::TENSOR_FLOAT16: + case V1_3::OperandType::TENSOR_INT32: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED: + case V1_3::OperandType::TENSOR_QUANT8_SYMM: + case V1_3::OperandType::TENSOR_QUANT16_ASYMM: + case V1_3::OperandType::TENSOR_QUANT16_SYMM: + case V1_3::OperandType::TENSOR_BOOL8: { NN_RET_CHECK(operand.extraParams.getDiscriminator() == - OperandExtraParams::hidl_discriminator::none) + V1_2::Operand::ExtraParams::hidl_discriminator::none) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " has incorrect extraParams: " << toString(operand.extraParams); } break; - case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: { + case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: { NN_RET_CHECK(operand.extraParams.getDiscriminator() == - OperandExtraParams::hidl_discriminator::channelQuant) + V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " without a Channel Quantization params"; auto& channelQuant = operand.extraParams.channelQuant(); @@ -151,9 +150,9 @@ static bool validateOperandExtraParams(const V1_3::Operand& operand, uint32_t in default: { if (isExtensionOperandType(operand.type)) { NN_RET_CHECK(operand.extraParams.getDiscriminator() == - OperandExtraParams::hidl_discriminator::extension || + V1_2::Operand::ExtraParams::hidl_discriminator::extension || operand.extraParams.getDiscriminator() == - OperandExtraParams::hidl_discriminator::none) + V1_2::Operand::ExtraParams::hidl_discriminator::none) << "Operand " << index << ": Extension operand of type " << getOperandTypeName(operand.type) << " has incorrect extraParams: " << toString(operand.extraParams); @@ -165,10 +164,11 @@ static bool validateOperandExtraParams(const V1_3::Operand& operand, uint32_t in } template <typename VersionedOperand> -static bool validateOperands(const hidl_vec<VersionedOperand>& operands, - const hidl_vec<uint8_t>& operandValues, - const hidl_vec<hidl_memory>& pools, - const hidl_vec<Subgraph>& subgraphs, bool allowUnspecifiedRank) { +static bool validateOperands(const hardware::hidl_vec<VersionedOperand>& operands, + const hardware::hidl_vec<uint8_t>& operandValues, + const hardware::hidl_vec<hardware::hidl_memory>& pools, + const hardware::hidl_vec<V1_3::Subgraph>& subgraphs, + bool allowUnspecifiedRank) { uint32_t index = 0; MemoryAccessVerifier poolVerifier(pools); for (auto& versionedOperand : operands) { @@ -182,13 +182,13 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, V1_3::Operand operand = convertToV1_3(versionedOperand); // Validate type and dimensions. switch (operand.type) { - case OperandType::FLOAT16: - case OperandType::FLOAT32: - case OperandType::INT32: - case OperandType::UINT32: - case OperandType::BOOL: - case OperandType::SUBGRAPH: - case OperandType::OEM: { + case V1_3::OperandType::FLOAT16: + case V1_3::OperandType::FLOAT32: + case V1_3::OperandType::INT32: + case V1_3::OperandType::UINT32: + case V1_3::OperandType::BOOL: + case V1_3::OperandType::SUBGRAPH: + case V1_3::OperandType::OEM: { size_t count = operand.dimensions.size(); if (count != 0) { LOG(ERROR) << "Operand " << index << ": Scalar data has dimensions of rank " @@ -197,19 +197,20 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, } break; } - case OperandType::TENSOR_FLOAT16: - case OperandType::TENSOR_FLOAT32: - case OperandType::TENSOR_INT32: - case OperandType::TENSOR_QUANT8_ASYMM: - case OperandType::TENSOR_QUANT8_ASYMM_SIGNED: - case OperandType::TENSOR_QUANT8_SYMM: - case OperandType::TENSOR_QUANT16_ASYMM: - case OperandType::TENSOR_QUANT16_SYMM: - case OperandType::TENSOR_BOOL8: - case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: - case OperandType::TENSOR_OEM_BYTE: { - if ((!allowUnspecifiedRank || operand.lifetime == OperandLifeTime::CONSTANT_COPY || - operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE) && + case V1_3::OperandType::TENSOR_FLOAT16: + case V1_3::OperandType::TENSOR_FLOAT32: + case V1_3::OperandType::TENSOR_INT32: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED: + case V1_3::OperandType::TENSOR_QUANT8_SYMM: + case V1_3::OperandType::TENSOR_QUANT16_ASYMM: + case V1_3::OperandType::TENSOR_QUANT16_SYMM: + case V1_3::OperandType::TENSOR_BOOL8: + case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case V1_3::OperandType::TENSOR_OEM_BYTE: { + if ((!allowUnspecifiedRank || + operand.lifetime == V1_3::OperandLifeTime::CONSTANT_COPY || + operand.lifetime == V1_3::OperandLifeTime::CONSTANT_REFERENCE) && operand.dimensions.size() == 0) { LOG(ERROR) << "Operand " << index << ": Tensor has dimensions of rank 0"; return false; @@ -227,16 +228,16 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, // Validate the scale. switch (operand.type) { - case OperandType::FLOAT16: - case OperandType::FLOAT32: - case OperandType::INT32: - case OperandType::UINT32: - case OperandType::BOOL: - case OperandType::SUBGRAPH: - case OperandType::TENSOR_FLOAT16: - case OperandType::TENSOR_FLOAT32: - case OperandType::TENSOR_BOOL8: - case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case V1_3::OperandType::FLOAT16: + case V1_3::OperandType::FLOAT32: + case V1_3::OperandType::INT32: + case V1_3::OperandType::UINT32: + case V1_3::OperandType::BOOL: + case V1_3::OperandType::SUBGRAPH: + case V1_3::OperandType::TENSOR_FLOAT16: + case V1_3::OperandType::TENSOR_FLOAT32: + case V1_3::OperandType::TENSOR_BOOL8: + case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: if (operand.scale != 0.f) { LOG(ERROR) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " with a non-zero scale (" @@ -244,7 +245,7 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandType::TENSOR_INT32: + case V1_3::OperandType::TENSOR_INT32: // TENSOR_INT32 may be used with or without scale, depending on the operation. if (operand.scale < 0.f) { LOG(ERROR) << "Operand " << index << ": Operand of type " @@ -252,11 +253,11 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandType::TENSOR_QUANT8_ASYMM: - case OperandType::TENSOR_QUANT8_ASYMM_SIGNED: - case OperandType::TENSOR_QUANT8_SYMM: - case OperandType::TENSOR_QUANT16_ASYMM: - case OperandType::TENSOR_QUANT16_SYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED: + case V1_3::OperandType::TENSOR_QUANT8_SYMM: + case V1_3::OperandType::TENSOR_QUANT16_ASYMM: + case V1_3::OperandType::TENSOR_QUANT16_SYMM: if (operand.scale <= 0.f) { LOG(ERROR) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " with a non-positive scale"; @@ -277,18 +278,18 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, // Validate the zeroPoint. switch (operand.type) { - case OperandType::FLOAT16: - case OperandType::FLOAT32: - case OperandType::INT32: - case OperandType::UINT32: - case OperandType::BOOL: - case OperandType::SUBGRAPH: - case OperandType::TENSOR_FLOAT16: - case OperandType::TENSOR_FLOAT32: - case OperandType::TENSOR_INT32: - case OperandType::TENSOR_BOOL8: - case OperandType::TENSOR_QUANT8_SYMM: - case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: + case V1_3::OperandType::FLOAT16: + case V1_3::OperandType::FLOAT32: + case V1_3::OperandType::INT32: + case V1_3::OperandType::UINT32: + case V1_3::OperandType::BOOL: + case V1_3::OperandType::SUBGRAPH: + case V1_3::OperandType::TENSOR_FLOAT16: + case V1_3::OperandType::TENSOR_FLOAT32: + case V1_3::OperandType::TENSOR_INT32: + case V1_3::OperandType::TENSOR_BOOL8: + case V1_3::OperandType::TENSOR_QUANT8_SYMM: + case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: if (operand.zeroPoint != 0) { LOG(ERROR) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " with a non-zero zeroPoint " @@ -296,7 +297,7 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandType::TENSOR_QUANT8_ASYMM: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM: if (operand.zeroPoint < 0 || operand.zeroPoint > 255) { LOG(ERROR) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " with an invalid zeroPoint " @@ -304,7 +305,7 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandType::TENSOR_QUANT8_ASYMM_SIGNED: + case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED: if (operand.zeroPoint < -128 || operand.zeroPoint > 127) { LOG(ERROR) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " with an invalid zeroPoint " @@ -312,7 +313,7 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandType::TENSOR_QUANT16_ASYMM: + case V1_3::OperandType::TENSOR_QUANT16_ASYMM: if (operand.zeroPoint < 0 || operand.zeroPoint > 65535) { LOG(ERROR) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " with an invalid zeroPoint " @@ -320,7 +321,7 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandType::TENSOR_QUANT16_SYMM: + case V1_3::OperandType::TENSOR_QUANT16_SYMM: if (operand.zeroPoint != 0) { LOG(ERROR) << "Operand " << index << ": Operand of type " << getOperandTypeName(operand.type) << " with a non-zero zeroPoint " @@ -342,9 +343,9 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, NN_RET_CHECK(validateOperandExtraParams(operand, index)); // Validate the lifetime and the location. - const DataLocation& location = operand.location; + const V1_0::DataLocation& location = operand.location; switch (operand.lifetime) { - case OperandLifeTime::CONSTANT_COPY: + case V1_3::OperandLifeTime::CONSTANT_COPY: if (location.poolIndex != 0) { LOG(ERROR) << "Operand " << index << ": CONSTANT_COPY with a non-zero poolIndex " @@ -360,15 +361,15 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandLifeTime::CONSTANT_REFERENCE: + case V1_3::OperandLifeTime::CONSTANT_REFERENCE: if (!poolVerifier.validate(location)) { return false; } break; - case OperandLifeTime::TEMPORARY_VARIABLE: - case OperandLifeTime::SUBGRAPH_INPUT: - case OperandLifeTime::SUBGRAPH_OUTPUT: - case OperandLifeTime::NO_VALUE: + case V1_3::OperandLifeTime::TEMPORARY_VARIABLE: + case V1_3::OperandLifeTime::SUBGRAPH_INPUT: + case V1_3::OperandLifeTime::SUBGRAPH_OUTPUT: + case V1_3::OperandLifeTime::NO_VALUE: if (location.poolIndex != 0 || location.offset != 0 || location.length != 0) { LOG(ERROR) << "Operand " << index << ": Unexpected poolIndex " << location.poolIndex << ", offset " << location.offset @@ -377,14 +378,14 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, return false; } break; - case OperandLifeTime::SUBGRAPH: { + case V1_3::OperandLifeTime::SUBGRAPH: { if (location.poolIndex != 0) { LOG(ERROR) << "Operand " << index << ": SUBGRAPH with a non-zero poolIndex " << location.poolIndex; return false; } if (location.offset >= subgraphs.size()) { - LOG(ERROR) << "Subgraph index out of range: " << location.offset + LOG(ERROR) << "Model::Subgraph index out of range: " << location.offset << " >= " << subgraphs.size(); return false; } @@ -401,8 +402,8 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, } // Make sure SUBGRAPH operand type and lifetime always go together. - if ((operand.type == OperandType::SUBGRAPH) != - (operand.lifetime == OperandLifeTime::SUBGRAPH)) { + if ((operand.type == V1_3::OperandType::SUBGRAPH) != + (operand.lifetime == V1_3::OperandLifeTime::SUBGRAPH)) { LOG(ERROR) << "Operand " << index << ": Operand of type " << toString(operand.type) << " cannot have lifetime " << toString(operand.lifetime); return false; @@ -410,10 +411,10 @@ static bool validateOperands(const hidl_vec<VersionedOperand>& operands, // For constants, validate that the length is as expected. The other lifetimes // expect the length to be 0. Don't validate for OEM types. - if (operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE || - operand.lifetime == OperandLifeTime::CONSTANT_COPY) { - if (!isExtensionOperandType(operand.type) && operand.type != OperandType::OEM && - operand.type != OperandType::TENSOR_OEM_BYTE) { + if (operand.lifetime == V1_3::OperandLifeTime::CONSTANT_REFERENCE || + operand.lifetime == V1_3::OperandLifeTime::CONSTANT_COPY) { + if (!isExtensionOperandType(operand.type) && operand.type != V1_3::OperandType::OEM && + operand.type != V1_3::OperandType::TENSOR_OEM_BYTE) { uint32_t expectedLength = nonExtensionOperandSizeOfData(operand); if (location.length != expectedLength) { LOG(ERROR) << "Operand " << index << ": For operand " << toString(operand) @@ -446,19 +447,22 @@ static HalVersion getHalVersion(const V1_3::Operation&) { } template <typename VersionedOperation> -static bool validateOperations(const hidl_vec<VersionedOperation>& operations, - const hidl_vec<Operand>& operands, - const hidl_vec<Subgraph>& subgraphs, ValidationMode mode) { - auto isValidSubgraphReference = [&subgraphs](const Operand& modelOperand) -> bool { +static bool validateOperations(const hardware::hidl_vec<VersionedOperation>& operations, + const hardware::hidl_vec<V1_3::Operand>& operands, + const hardware::hidl_vec<V1_3::Subgraph>& subgraphs, + ValidationMode mode) { + auto canonicalSubgraphs = uncheckedConvert(subgraphs); + auto isValidSubgraphReference = [&canonicalSubgraphs](const Operand& modelOperand) -> bool { NN_RET_CHECK(modelOperand.type == OperandType::SUBGRAPH) - << "Unexpected operand type: " << toString(modelOperand.type); - NN_RET_CHECK_LT(modelOperand.location.offset, subgraphs.size()) + << "Unexpected operand type: " << modelOperand.type; + NN_RET_CHECK_LT(modelOperand.location.offset, canonicalSubgraphs.size()) << "Invalid subgraph reference"; return true; }; - auto getSubgraph = [&subgraphs](const Operand& modelOperand) -> const Subgraph* { - CHECK_LT(modelOperand.location.offset, subgraphs.size()); - return &subgraphs[modelOperand.location.offset]; + auto getSubgraph = + [&canonicalSubgraphs](const Operand& modelOperand) -> const Model::Subgraph* { + CHECK_LT(modelOperand.location.offset, canonicalSubgraphs.size()); + return &canonicalSubgraphs[modelOperand.location.offset]; }; auto getInputCount = [&getSubgraph](const Operand& modelOperand) -> uint32_t { return getSubgraph(modelOperand)->inputIndexes.size(); @@ -468,32 +472,33 @@ static bool validateOperations(const hidl_vec<VersionedOperation>& operations, }; auto getInputOperand = [&getSubgraph](const Operand& modelOperand, uint32_t index) -> const Operand* { - const Subgraph& subgraph = *getSubgraph(modelOperand); + const Model::Subgraph& subgraph = *getSubgraph(modelOperand); CHECK_LT(subgraph.inputIndexes[index], subgraph.operands.size()); return &subgraph.operands[subgraph.inputIndexes[index]]; }; auto getOutputOperand = [&getSubgraph](const Operand& modelOperand, uint32_t index) -> const Operand* { - const Subgraph& subgraph = *getSubgraph(modelOperand); + const Model::Subgraph& subgraph = *getSubgraph(modelOperand); CHECK_LT(subgraph.outputIndexes[index], subgraph.operands.size()); return &subgraph.operands[subgraph.outputIndexes[index]]; }; for (auto& op : operations) { // TODO Validate the shapes and any known values. This is currently // done in CpuExecutor but should be done here for all drivers. - int error = validateOperation( - static_cast<int32_t>(op.type), op.inputs.size(), - op.inputs.size() > 0 ? op.inputs.data() : nullptr, op.outputs.size(), - op.outputs.size() > 0 ? op.outputs.data() : nullptr, operands, getHalVersion(op), - {.isValidSubgraphReference = isValidSubgraphReference, - .getSubgraphInputCount = getInputCount, - .getSubgraphOutputCount = getOutputCount, - .getSubgraphInputOperand = getInputOperand, - .getSubgraphOutputOperand = getOutputOperand, - // 1.3 HAL does not support CF operations with operands of - // unknown size. See http://b/132458982#comment63. - .allowControlFlowOperationWithOperandOfUnknownSize = - mode == ValidationMode::RUNTIME}); + int error = validateOperation(static_cast<int32_t>(op.type), op.inputs.size(), + op.inputs.size() > 0 ? op.inputs.data() : nullptr, + op.outputs.size(), + op.outputs.size() > 0 ? op.outputs.data() : nullptr, + uncheckedConvert(operands), getHalVersion(op), + {.isValidSubgraphReference = isValidSubgraphReference, + .getSubgraphInputCount = getInputCount, + .getSubgraphOutputCount = getOutputCount, + .getSubgraphInputOperand = getInputOperand, + .getSubgraphOutputOperand = getOutputOperand, + // 1.3 HAL does not support CF operations with operands of + // unknown size. See http://b/132458982#comment63. + .allowControlFlowOperationWithOperandOfUnknownSize = + mode == ValidationMode::RUNTIME}); if (error != ANEURALNETWORKS_NO_ERROR) { LOG(ERROR) << "Invalid operation " << toString(op.type); return false; @@ -503,9 +508,9 @@ static bool validateOperations(const hidl_vec<VersionedOperation>& operations, // but it is retained here in order to emit more informative // error messages. for (uint32_t i : op.outputs) { - const Operand& operand = operands[i]; - if (operand.lifetime != OperandLifeTime::TEMPORARY_VARIABLE && - operand.lifetime != OperandLifeTime::SUBGRAPH_OUTPUT) { + const V1_3::Operand& operand = operands[i]; + if (operand.lifetime != V1_3::OperandLifeTime::TEMPORARY_VARIABLE && + operand.lifetime != V1_3::OperandLifeTime::SUBGRAPH_OUTPUT) { LOG(ERROR) << "Writing to operand " << i << " with incompatible lifetime " << toString(operand.lifetime); return false; @@ -515,7 +520,7 @@ static bool validateOperations(const hidl_vec<VersionedOperation>& operations, return true; } -bool validatePool(const hidl_memory& pool, HalVersion ver) { +bool validatePool(const hardware::hidl_memory& pool, HalVersion ver) { const auto& name = pool.name(); if (name != "ashmem" && name != "mmap_fd" && ((ver < HalVersion::V1_2) || @@ -532,9 +537,9 @@ bool validatePool(const hidl_memory& pool, HalVersion ver) { bool validatePool(const V1_3::Request::MemoryPool& pool, HalVersion ver) { switch (pool.getDiscriminator()) { - case Request::MemoryPool::hidl_discriminator::hidlMemory: + case V1_3::Request::MemoryPool::hidl_discriminator::hidlMemory: return validatePool(pool.hidlMemory(), ver); - case Request::MemoryPool::hidl_discriminator::token: + case V1_3::Request::MemoryPool::hidl_discriminator::token: return pool.token() > 0; } LOG(FATAL) << "unknown MemoryPool discriminator"; @@ -542,20 +547,21 @@ bool validatePool(const V1_3::Request::MemoryPool& pool, HalVersion ver) { } template <class T_MemoryPool> -static bool validatePools(const hidl_vec<T_MemoryPool>& pools, HalVersion ver) { +static bool validatePools(const hardware::hidl_vec<T_MemoryPool>& pools, HalVersion ver) { return std::all_of(pools.begin(), pools.end(), [ver](const auto& pool) { return validatePool(pool, ver); }); } -static bool validateModelInputOutputs(const hidl_vec<uint32_t> indexes, - const hidl_vec<Operand>& operands, OperandLifeTime lifetime) { +static bool validateModelInputOutputs(const hardware::hidl_vec<uint32_t> indexes, + const hardware::hidl_vec<V1_3::Operand>& operands, + V1_3::OperandLifeTime lifetime) { const size_t operandCount = operands.size(); for (uint32_t i : indexes) { if (i >= operandCount) { LOG(ERROR) << "Model input or output index out of range: " << i << "/" << operandCount; return false; } - const Operand& operand = operands[i]; + const V1_3::Operand& operand = operands[i]; if (operand.lifetime != lifetime) { LOG(ERROR) << "Model input or output operand " << i << " has lifetime of " << toString(operand.lifetime) << " instead of the expected " @@ -596,12 +602,12 @@ static bool validateGraph(const VersionedModelOrSubgraph& model) { // mark known operands for (size_t i = 0; i < model.operands.size(); ++i) { const auto& operand = model.operands[i]; - const OperandLifeTime lifetime = convertToV1_3(operand.lifetime); - operandValueKnown[i] = lifetime == OperandLifeTime::SUBGRAPH_INPUT || - lifetime == OperandLifeTime::CONSTANT_COPY || - lifetime == OperandLifeTime::CONSTANT_REFERENCE || - lifetime == OperandLifeTime::NO_VALUE || - lifetime == OperandLifeTime::SUBGRAPH; + const V1_3::OperandLifeTime lifetime = convertToV1_3(operand.lifetime); + operandValueKnown[i] = lifetime == V1_3::OperandLifeTime::SUBGRAPH_INPUT || + lifetime == V1_3::OperandLifeTime::CONSTANT_COPY || + lifetime == V1_3::OperandLifeTime::CONSTANT_REFERENCE || + lifetime == V1_3::OperandLifeTime::NO_VALUE || + lifetime == V1_3::OperandLifeTime::SUBGRAPH; } // Validate that operations are sorted into execution order. @@ -672,8 +678,8 @@ static bool checkNoReferenceCycles(const V1_3::Model& model, const V1_3::Subgrap LOG(ERROR) << "Model contains a circular subgraph reference"; return false; } - for (const Operand& operand : subgraph.operands) { - if (operand.lifetime == OperandLifeTime::SUBGRAPH) { + for (const V1_3::Operand& operand : subgraph.operands) { + if (operand.lifetime == V1_3::OperandLifeTime::SUBGRAPH) { uint32_t refSubgraphIndex = operand.location.offset; if (!checkNoReferenceCycles(model, model.referenced[refSubgraphIndex], path)) { return false; @@ -699,14 +705,14 @@ bool validateModel(const T_Model& model, ValidationMode mode) { } // We only need versioned operands for their validation. For all the other // validations we can use operands upcasted to the latest version. - const hidl_vec<Operand> latestVersionOperands = convertToV1_3(model.operands); + const hardware::hidl_vec<V1_3::Operand> latestVersionOperands = convertToV1_3(model.operands); return (validateOperands(model.operands, model.operandValues, model.pools, /*subgraphs=*/{}, /*allowUnspecifiedRank=*/version >= HalVersion::V1_2) && validateOperations(model.operations, latestVersionOperands, /*subgraphs=*/{}, mode) && validateModelInputOutputs(model.inputIndexes, latestVersionOperands, - OperandLifeTime::SUBGRAPH_INPUT) && + V1_3::OperandLifeTime::SUBGRAPH_INPUT) && validateModelInputOutputs(model.outputIndexes, latestVersionOperands, - OperandLifeTime::SUBGRAPH_OUTPUT) && + V1_3::OperandLifeTime::SUBGRAPH_OUTPUT) && validatePools(model.pools, version) && validateGraph(model)); } @@ -721,15 +727,15 @@ bool validateModel(const V1_3::Model& model, ValidationMode mode) { LOG(ERROR) << "Invalid empty model."; return false; } - auto validateSubgraph = [&model, mode](const Subgraph& subgraph) -> bool { + auto validateSubgraph = [&model, mode](const V1_3::Subgraph& subgraph) -> bool { return (validateOperands(subgraph.operands, model.operandValues, model.pools, model.referenced, /*allowUnspecifiedRank=*/true) && validateOperations(subgraph.operations, subgraph.operands, model.referenced, mode) && validateModelInputOutputs(subgraph.inputIndexes, subgraph.operands, - OperandLifeTime::SUBGRAPH_INPUT) && + V1_3::OperandLifeTime::SUBGRAPH_INPUT) && validateModelInputOutputs(subgraph.outputIndexes, subgraph.operands, - OperandLifeTime::SUBGRAPH_OUTPUT) && + V1_3::OperandLifeTime::SUBGRAPH_OUTPUT) && validateGraph(subgraph)); }; return (validateSubgraph(model.main) && @@ -740,11 +746,11 @@ bool validateModel(const V1_3::Model& model, ValidationMode mode) { // Validates the arguments of a request. type is either "input" or "output" and is used // for printing error messages. The operandIndexes is the appropriate array of input // or output operand indexes that was passed to the ANeuralNetworksModel_identifyInputsAndOutputs. -static bool validateRequestArguments(const hidl_vec<RequestArgument>& requestArguments, - const hidl_vec<uint32_t>& operandIndexes, - const hidl_vec<Operand>& operands, - const MemoryAccessVerifier& poolVerifier, - bool allowUnspecified, const char* type) { +static bool validateRequestArguments( + const hardware::hidl_vec<V1_0::RequestArgument>& requestArguments, + const hardware::hidl_vec<uint32_t>& operandIndexes, + const hardware::hidl_vec<V1_3::Operand>& operands, const MemoryAccessVerifier& poolVerifier, + bool allowUnspecified, const char* type) { // The request should specify as many arguments as were described in the model. const size_t requestArgumentCount = requestArguments.size(); if (requestArgumentCount != operandIndexes.size()) { @@ -754,13 +760,13 @@ static bool validateRequestArguments(const hidl_vec<RequestArgument>& requestArg } for (size_t requestArgumentIndex = 0; requestArgumentIndex < requestArgumentCount; requestArgumentIndex++) { - const RequestArgument& requestArgument = requestArguments[requestArgumentIndex]; - const DataLocation& location = requestArgument.location; + const V1_0::RequestArgument& requestArgument = requestArguments[requestArgumentIndex]; + const V1_0::DataLocation& location = requestArgument.location; // Get the operand index for this argument. We extract it from the list // that was provided in the call to ANeuralNetworksModel_identifyInputsAndOutputs. // We assume in this function that the model has been validated already. const uint32_t operandIndex = operandIndexes[requestArgumentIndex]; - const Operand& operand = operands[operandIndex]; + const V1_3::Operand& operand = operands[operandIndex]; if (requestArgument.hasNoValue) { if (location.poolIndex != 0 || location.offset != 0 || location.length != 0 || requestArgument.dimensions.size() != 0) { @@ -861,9 +867,9 @@ bool validateRequest(const V1_3::Request& request, const V1_3::Model& model, } bool validateMemoryDesc(const V1_3::BufferDesc& desc, - const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, - const hidl_vec<V1_3::BufferRole>& inputRoles, - const hidl_vec<V1_3::BufferRole>& outputRoles, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, + const hardware::hidl_vec<V1_3::BufferRole>& inputRoles, + const hardware::hidl_vec<V1_3::BufferRole>& outputRoles, std::function<const V1_3::Model*(const sp<V1_3::IPreparedModel>&)> getModel, std::set<PreparedModelRole>* preparedModelRoles, V1_3::Operand* combinedOperand) { @@ -939,14 +945,15 @@ bool validateMemoryDesc(const V1_3::BufferDesc& desc, return true; } -bool validateExecutionPreference(ExecutionPreference preference) { - return preference == ExecutionPreference::LOW_POWER || - preference == ExecutionPreference::FAST_SINGLE_ANSWER || - preference == ExecutionPreference::SUSTAINED_SPEED; +bool validateExecutionPreference(V1_1::ExecutionPreference preference) { + return preference == V1_1::ExecutionPreference::LOW_POWER || + preference == V1_1::ExecutionPreference::FAST_SINGLE_ANSWER || + preference == V1_1::ExecutionPreference::SUSTAINED_SPEED; } -bool validatePriority(Priority priority) { - return priority == Priority::LOW || priority == Priority::MEDIUM || priority == Priority::HIGH; +bool validatePriority(V1_3::Priority priority) { + return priority == V1_3::Priority::LOW || priority == V1_3::Priority::MEDIUM || + priority == V1_3::Priority::HIGH; } bool validOperandType(V1_0::OperandType operandType) { diff --git a/nn/common/include/BufferTracker.h b/nn/common/include/BufferTracker.h index feabda643..60432caaf 100644 --- a/nn/common/include/BufferTracker.h +++ b/nn/common/include/BufferTracker.h @@ -37,23 +37,23 @@ namespace android::nn { class ManagedBuffer { public: static std::shared_ptr<ManagedBuffer> create(uint32_t size, std::set<PreparedModelRole> roles, - const hal::Operand& operand); + const Operand& operand); // Prefer ManagedBuffer::create. ManagedBuffer(std::unique_ptr<uint8_t[]> buffer, uint32_t size, - std::set<PreparedModelRole> roles, const hal::Operand& operand); + std::set<PreparedModelRole> roles, const Operand& operand); RunTimePoolInfo createRunTimePoolInfo() const { return RunTimePoolInfo::createFromExistingBuffer(kBuffer.get(), kSize); } // "poolIndex" is the index of this buffer in the request.pools. - hal::ErrorStatus validateRequest(uint32_t poolIndex, const hal::Request& request, - const hal::IPreparedModel* preparedModel) const; + ErrorStatus validateRequest(uint32_t poolIndex, const Request& request, + const V1_3::IPreparedModel* preparedModel) const; // "size" is the byte size of the hidl_memory provided to the copyFrom or copyTo method. - hal::ErrorStatus validateCopyFrom(const std::vector<uint32_t>& dimensions, uint32_t size) const; - hal::ErrorStatus validateCopyTo(uint32_t size) const; + ErrorStatus validateCopyFrom(const std::vector<uint32_t>& dimensions, uint32_t size) const; + ErrorStatus validateCopyTo(uint32_t size) const; bool updateDimensions(const std::vector<uint32_t>& dimensions); void setInitialized(bool initialized); @@ -63,7 +63,7 @@ class ManagedBuffer { const std::unique_ptr<uint8_t[]> kBuffer; const uint32_t kSize; const std::set<PreparedModelRole> kRoles; - const hal::OperandType kOperandType; + const OperandType kOperandType; const std::vector<uint32_t> kInitialDimensions; std::vector<uint32_t> mUpdatedDimensions; bool mInitialized = false; diff --git a/nn/common/include/CpuExecutor.h b/nn/common/include/CpuExecutor.h index edb233217..094572921 100644 --- a/nn/common/include/CpuExecutor.h +++ b/nn/common/include/CpuExecutor.h @@ -25,10 +25,10 @@ #include <vector> #include "ControlFlow.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Utils.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -37,7 +37,7 @@ namespace nn { // may change during execution. struct RunTimeOperandInfo { // TODO Storing the type here is redundant, as it won't change during execution. - hal::OperandType type; + OperandType type; // The type and dimensions of the operand. The dimensions can // change at runtime. We include the type because it's useful // to pass together with the dimension to the functions implementing @@ -64,14 +64,14 @@ struct RunTimeOperandInfo { // The length of the buffer. uint32_t length; // Whether this is a temporary variable, a model input, a constant, etc. - hal::OperandLifeTime lifetime; + Operand::LifeTime lifetime; // Keeps track of how many operations have yet to make use // of this temporary variable. When the count is decremented to 0, // we free the buffer. For non-temporary variables, this count is // always 0. uint32_t numberOfUsesLeft; - hal::OperandExtraParams extraParams; + Operand::ExtraParams extraParams; Shape shape() const { return { @@ -84,7 +84,7 @@ struct RunTimeOperandInfo { } bool isSufficient() const { - if (isExtensionOperandType(type)) { + if (isExtension(type)) { // We don't know sizes of extension types. return true; } @@ -98,19 +98,20 @@ struct RunTimeOperandInfo { // may reference the same region of memory by either: // (1) copying an existing RunTimePoolInfo object, or // (2) creating multiple RunTimePoolInfo objects from the same memory resource -// (e.g., "createFromHidlMemory" or "createFromExistingBuffer") +// (e.g., "createFromMemory" or "createFromExistingBuffer") // -// If the underlying region of memory is mapped by "createFromHidlMemory", the +// If the underlying region of memory is mapped by "createFromMemory", the // mapping will be sustained until it is no longer referenced by any // RunTimePoolInfo objects. class RunTimePoolInfo { public: - static std::optional<RunTimePoolInfo> createFromHidlMemory(const hal::hidl_memory& hidlMemory); + static std::optional<RunTimePoolInfo> createFromMemory(const Memory& memory); static RunTimePoolInfo createFromExistingBuffer(uint8_t* buffer, uint32_t size = 0); uint8_t* getBuffer() const; bool flush() const; - const hal::hidl_memory& getHidlMemory() const; + // TODO(b/169672209): "const Memory& getMemory() const;" + Memory getMemory() const; uint32_t getSize() const; private: @@ -120,11 +121,20 @@ class RunTimePoolInfo { std::shared_ptr<const RunTimePoolInfoImpl> mImpl; }; -bool setRunTimePoolInfosFromHidlMemories(std::vector<RunTimePoolInfo>* poolInfos, - const hal::hidl_vec<hal::hidl_memory>& pools); +bool setRunTimePoolInfosFromCanonicalMemories(std::vector<RunTimePoolInfo>* poolInfos, + const std::vector<Memory>& pools); + +// DEPRECATED. Use setRunTimePoolInfosFromCanonicalMemories(). +// +// Used by external code. +inline bool setRunTimePoolInfosFromHidlMemories( + std::vector<RunTimePoolInfo>* poolInfos, + const hardware::hidl_vec<hardware::hidl_memory>& pools) { + return setRunTimePoolInfosFromCanonicalMemories(poolInfos, uncheckedConvert(pools)); +} bool setRunTimePoolInfosFromMemoryPools(std::vector<RunTimePoolInfo>* poolInfos, - const hal::hidl_vec<hal::Request::MemoryPool>& pools); + const std::vector<Request::MemoryPool>& pools); // This class is used to execute a model on the CPU. class CpuExecutor { @@ -146,11 +156,11 @@ class CpuExecutor { // specified in the constructor. // The model must outlive the executor. We prevent it from being modified // while this is executing. - int run(const hal::Model& model, const hal::Request& request, + int run(const Model& model, const Request& request, const std::vector<RunTimePoolInfo>& modelPoolInfos, const std::vector<RunTimePoolInfo>& requestPoolInfos); - const std::vector<hal::OutputShape>& getOutputShapes() const { + const std::vector<OutputShape>& getOutputShapes() const { CHECK(mFinished) << "getOutputShapes() called by an unfinished CpuExecutor."; return mOutputShapes; } @@ -160,31 +170,31 @@ class CpuExecutor { private: // Creates runtime info from what's in the model. - std::vector<RunTimeOperandInfo> initializeRunTimeInfo(const hal::Subgraph& subgraph); + std::vector<RunTimeOperandInfo> initializeRunTimeInfo(const Model::Subgraph& subgraph); // Adjusts the runtime info for the arguments passed to the model, // modifying the buffer location, and possibly the dimensions. void updateForArguments(const std::vector<uint32_t>& indexes, - const hal::hidl_vec<hal::RequestArgument>& arguments, + const std::vector<Request::Argument>& arguments, const std::vector<RunTimePoolInfo>& requestPoolInfos, RunTimeOperandInfo* operands); // Runs one subgraph. - int executeSubgraph(const hal::Subgraph& subgraph, RunTimeOperandInfo* operands); + int executeSubgraph(const Model::Subgraph& subgraph, RunTimeOperandInfo* operands); // Runs one operation of the graph. - int executeOperation(const hal::Operation& operation, RunTimeOperandInfo* operands); - int executeIfOperation(const hal::Operation& operation, RunTimeOperandInfo* operands); - int executeWhileOperation(const hal::Operation& operation, RunTimeOperandInfo* operands); + int executeOperation(const Operation& operation, RunTimeOperandInfo* operands); + int executeIfOperation(const Operation& operation, RunTimeOperandInfo* operands); + int executeWhileOperation(const Operation& operation, RunTimeOperandInfo* operands); void setOutputShapes(const std::vector<uint32_t>& outputIndexes, const std::vector<RunTimeOperandInfo>& operands); // Compile-time operand value information used by initializeRunTimeInfo. // The fields are only valid while run() is being executed. - const hal::hidl_vec<uint8_t>* mModelOperandValues = nullptr; + const uint8_t* mModelOperandValues = nullptr; const std::vector<RunTimePoolInfo>* mModelPoolInfos = nullptr; - const hal::hidl_vec<hal::Subgraph>* mReferencedSubgraphs = nullptr; + const std::vector<Model::Subgraph>* mReferencedSubgraphs = nullptr; // The output operand shapes returning to the runtime. - std::vector<hal::OutputShape> mOutputShapes; + std::vector<OutputShape> mOutputShapes; // Whether execution is finished and mOutputShapes is ready bool mFinished = false; @@ -259,17 +269,16 @@ T getScalarDataWithDefault(const RunTimeOperandInfo& info, T defaultValue) { } inline bool IsNullInput(const RunTimeOperandInfo* input) { - return input->lifetime == hal::OperandLifeTime::NO_VALUE; + return input->lifetime == Operand::LifeTime::NO_VALUE; } -inline int NumInputsWithValues(const hal::Operation& operation, - const RunTimeOperandInfo* operands) { +inline int NumInputsWithValues(const Operation& operation, const RunTimeOperandInfo* operands) { const std::vector<uint32_t>& inputs = operation.inputs; return std::count_if(inputs.begin(), inputs.end(), [&operands](uint32_t i) { return !IsNullInput(&operands[i]); }); } -inline int NumOutputs(const hal::Operation& operation) { +inline int NumOutputs(const Operation& operation) { return operation.outputs.size(); } @@ -281,12 +290,12 @@ inline uint32_t SizeOfDimension(const RunTimeOperandInfo* operand, int i) { return operand->shape().dimensions[i]; } -inline RunTimeOperandInfo* GetInput(const hal::Operation& operation, RunTimeOperandInfo* operands, +inline RunTimeOperandInfo* GetInput(const Operation& operation, RunTimeOperandInfo* operands, int index) { return &operands[operation.inputs[index]]; } -inline RunTimeOperandInfo* GetOutput(const hal::Operation& operation, RunTimeOperandInfo* operands, +inline RunTimeOperandInfo* GetOutput(const Operation& operation, RunTimeOperandInfo* operands, int index) { return &operands[operation.outputs[index]]; } diff --git a/nn/common/include/GraphDump.h b/nn/common/include/GraphDump.h index 207afe507..208b4ec18 100644 --- a/nn/common/include/GraphDump.h +++ b/nn/common/include/GraphDump.h @@ -17,10 +17,10 @@ #ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_GRAPH_DUMP_H #define ANDROID_FRAMEWORKS_ML_NN_COMMON_GRAPH_DUMP_H -#include <android/hardware/neuralnetworks/1.3/types.h> - #include <iostream> +#include "nnapi/Types.h" + namespace android { namespace nn { @@ -45,8 +45,7 @@ namespace nn { // A model input or output (operand) is shown in "reverse colors" -- // white text on a black background. // -void graphDump(const char* name, const ::android::hardware::neuralnetworks::V1_3::Model& model, - std::ostream* outStream = nullptr); +void graphDump(const char* name, const Model& model, std::ostream* outStream = nullptr); } // namespace nn } // namespace android diff --git a/nn/common/include/HalInterfaces.h b/nn/common/include/HalInterfaces.h index 4e3a3800b..8eeb23d6d 100644 --- a/nn/common/include/HalInterfaces.h +++ b/nn/common/include/HalInterfaces.h @@ -40,74 +40,20 @@ #include <functional> -namespace android::nn::hal { +namespace android::nn { -using android::sp; +namespace V1_0 = ::android::hardware::neuralnetworks::V1_0; +namespace V1_1 = ::android::hardware::neuralnetworks::V1_1; +namespace V1_2 = ::android::hardware::neuralnetworks::V1_2; +namespace V1_3 = ::android::hardware::neuralnetworks::V1_3; -using hardware::hidl_death_recipient; -using hardware::hidl_enum_range; -using hardware::hidl_handle; -using hardware::hidl_memory; -using hardware::hidl_string; -using hardware::hidl_vec; -using hardware::Return; -using hardware::Void; +using HalCacheToken = + hardware::hidl_array<uint8_t, + static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using HalDeviceFactory = std::function<sp<V1_0::IDevice>(bool blocking)>; -using hidl::memory::V1_0::IMemory; +inline constexpr V1_3::Priority kDefaultPriority13 = V1_3::Priority::MEDIUM; -namespace V1_0 = hardware::neuralnetworks::V1_0; -namespace V1_1 = hardware::neuralnetworks::V1_1; -namespace V1_2 = hardware::neuralnetworks::V1_2; -namespace V1_3 = hardware::neuralnetworks::V1_3; - -using V1_0::DataLocation; -using V1_0::DeviceStatus; -using V1_0::FusedActivationFunc; -using V1_0::PerformanceInfo; -using V1_0::RequestArgument; -using V1_1::ExecutionPreference; -using V1_2::Constant; -using V1_2::DeviceType; -using V1_2::Extension; -using V1_2::MeasureTiming; -using V1_2::OutputShape; -using V1_2::SymmPerChannelQuantParams; -using V1_2::Timing; -using V1_3::BufferDesc; -using V1_3::BufferRole; -using V1_3::Capabilities; -using V1_3::ErrorStatus; -using V1_3::IBuffer; -using V1_3::IDevice; -using V1_3::IExecutionCallback; -using V1_3::IFencedExecutionCallback; -using V1_3::IPreparedModel; -using V1_3::IPreparedModelCallback; -using V1_3::LoopTimeoutDurationNs; -using V1_3::Model; -using V1_3::Operand; -using V1_3::OperandLifeTime; -using V1_3::OperandType; -using V1_3::OperandTypeRange; -using V1_3::Operation; -using V1_3::OperationType; -using V1_3::OperationTypeRange; -using V1_3::OptionalTimeoutDuration; -using V1_3::OptionalTimePoint; -using V1_3::Priority; -using V1_3::Request; -using V1_3::Subgraph; -using ExtensionNameAndPrefix = V1_2::Model::ExtensionNameAndPrefix; -using ExtensionTypeEncoding = V1_2::Model::ExtensionTypeEncoding; -using OperandExtraParams = V1_2::Operand::ExtraParams; - -using CacheToken = - hardware::hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; -using DeviceFactory = std::function<sp<V1_0::IDevice>(bool blocking)>; -using ModelFactory = std::function<Model()>; - -inline constexpr Priority kDefaultPriority = Priority::MEDIUM; - -} // namespace android::nn::hal +} // namespace android::nn #endif // ANDROID_FRAMEWORKS_ML_NN_COMMON_HAL_INTERFACES_H diff --git a/nn/common/include/MetaModel.h b/nn/common/include/MetaModel.h index 154a453fd..3cb87f31d 100644 --- a/nn/common/include/MetaModel.h +++ b/nn/common/include/MetaModel.h @@ -17,9 +17,8 @@ #ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_META_MODEL_H #define ANDROID_FRAMEWORKS_ML_NN_COMMON_META_MODEL_H -#include "HalInterfaces.h" - #include <android-base/macros.h> + #include <functional> #include <map> #include <optional> @@ -27,6 +26,10 @@ #include <utility> #include <vector> +#include "HalInterfaces.h" +#include "Utils.h" +#include "nnapi/Types.h" + namespace android::nn { // The MetaModel class encapsulates a Model and provides machinery to create @@ -67,14 +70,15 @@ class MetaModel { template <class T_Model> using ReturnedSlice = std::optional<std::pair<T_Model, Mapper>>; - MetaModel(hal::Model model, bool strictSlicing) - : mHidlModel(std::move(model)), mStrictSlicing(strictSlicing) {} + MetaModel(Model model, bool strictSlicing) + : mModel(std::move(model)), mStrictSlicing(strictSlicing) {} - const hal::Model& getModel() const { return mHidlModel; } + const Model& getModel() const { return mModel; } - ReturnedSlice<hal::V1_0::Model> getSliceV1_0() const { return getSlice(&mSliceV1_0); } - ReturnedSlice<hal::V1_1::Model> getSliceV1_1() const { return getSlice(&mSliceV1_1); } - ReturnedSlice<hal::V1_2::Model> getSliceV1_2() const { return getSlice(&mSliceV1_2); } + ReturnedSlice<V1_0::Model> getSliceV1_0() const { return getSlice(&mSliceV1_0); } + ReturnedSlice<V1_1::Model> getSliceV1_1() const { return getSlice(&mSliceV1_1); } + ReturnedSlice<V1_2::Model> getSliceV1_2() const { return getSlice(&mSliceV1_2); } + ReturnedSlice<V1_3::Model> getSliceV1_3() const { return getSlice(&mSliceV1_3); } // Disallowing copy constructor and assignment operator is for efficiency, // not for correctness. The default copy constructor and assignment @@ -92,7 +96,7 @@ class MetaModel { MetaModel& operator=(MetaModel&&) = default; private: - hal::Model mHidlModel; + Model mModel; // mStrictSlicing controls validity checking. If the slicing algorithm // produces an invalid model (because something has gone wrong with the @@ -114,12 +118,20 @@ class MetaModel { using Operation = typename decltype(mHidlModel.operations)::value_type; using OperationType = decltype(Operation::type); }; - mutable Slice<hal::V1_0::Model> mSliceV1_0; - mutable Slice<hal::V1_1::Model> mSliceV1_1; - mutable Slice<hal::V1_2::Model> mSliceV1_2; + template <> + struct Slice<V1_3::Model> { // Trivial slice. + SliceState mState = SliceState::UNINITIALIZED; + V1_3::Model mHidlModel; + }; + mutable Slice<V1_0::Model> mSliceV1_0; + mutable Slice<V1_1::Model> mSliceV1_1; + mutable Slice<V1_2::Model> mSliceV1_2; + mutable Slice<V1_3::Model> mSliceV1_3; template <class T_SlicedModel> ReturnedSlice<T_SlicedModel> getSlice(Slice<T_SlicedModel>* slice) const; + template <> + ReturnedSlice<V1_3::Model> getSlice(Slice<V1_3::Model>* slice) const; template <class T_SlicedModel> Slice<T_SlicedModel> makeSlice() const; diff --git a/nn/common/include/OperationResolver.h b/nn/common/include/OperationResolver.h index ab70e4c3a..700513d13 100644 --- a/nn/common/include/OperationResolver.h +++ b/nn/common/include/OperationResolver.h @@ -25,7 +25,7 @@ namespace nn { // Encapsulates an operation implementation. struct OperationRegistration { - hal::OperationType type; + OperationType type; const char* name; // Validates operand types, shapes, and any values known during graph creation. @@ -47,7 +47,7 @@ struct OperationRegistration { bool allowZeroSizedInput = false; } flags; - OperationRegistration(hal::OperationType type, const char* name, + OperationRegistration(OperationType type, const char* name, std::function<bool(const IOperationValidationContext*)> validate, std::function<bool(IOperationExecutionContext*)> prepare, std::function<bool(IOperationExecutionContext*)> execute, Flag flags) @@ -62,7 +62,7 @@ struct OperationRegistration { // A registry of operation implementations. class IOperationResolver { public: - virtual const OperationRegistration* findOperation(hal::OperationType operationType) const = 0; + virtual const OperationRegistration* findOperation(OperationType operationType) const = 0; virtual ~IOperationResolver() {} }; @@ -86,7 +86,7 @@ class BuiltinOperationResolver : public IOperationResolver { return &instance; } - const OperationRegistration* findOperation(hal::OperationType operationType) const override; + const OperationRegistration* findOperation(OperationType operationType) const override; private: BuiltinOperationResolver(); @@ -116,11 +116,11 @@ class BuiltinOperationResolver : public IOperationResolver { // .allowZeroSizedInput = true); // #ifdef NN_INCLUDE_CPU_IMPLEMENTATION -#define NN_REGISTER_OPERATION(identifier, operationName, validate, prepare, execute, ...) \ - const OperationRegistration* register_##identifier() { \ - static OperationRegistration registration(hal::OperationType::identifier, operationName, \ - validate, prepare, execute, {__VA_ARGS__}); \ - return ®istration; \ +#define NN_REGISTER_OPERATION(identifier, operationName, validate, prepare, execute, ...) \ + const OperationRegistration* register_##identifier() { \ + static OperationRegistration registration(OperationType::identifier, operationName, \ + validate, prepare, execute, {__VA_ARGS__}); \ + return ®istration; \ } #else // This version ignores CPU execution logic (prepare and execute). @@ -129,7 +129,7 @@ class BuiltinOperationResolver : public IOperationResolver { #define NN_REGISTER_OPERATION(identifier, operationName, validate, unused_prepare, unused_execute, \ ...) \ const OperationRegistration* register_##identifier() { \ - static OperationRegistration registration(hal::OperationType::identifier, operationName, \ + static OperationRegistration registration(OperationType::identifier, operationName, \ validate, nullptr, nullptr, {__VA_ARGS__}); \ return ®istration; \ } diff --git a/nn/common/include/OperationsUtils.h b/nn/common/include/OperationsUtils.h index a8a07db9c..9b0a9bdaa 100644 --- a/nn/common/include/OperationsUtils.h +++ b/nn/common/include/OperationsUtils.h @@ -23,6 +23,7 @@ #include "HalInterfaces.h" #include "Utils.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -45,11 +46,11 @@ enum PaddingScheme { // Stores operand type information. "Shape" is a historical name. struct Shape { - hal::OperandType type = hal::OperandType::FLOAT32; + OperandType type = OperandType::FLOAT32; std::vector<uint32_t> dimensions; float scale = 0.0f; int32_t offset = 0; - hal::OperandExtraParams extraParams; + Operand::ExtraParams extraParams; }; // Provides information available during graph creation to validate an operation. @@ -76,12 +77,12 @@ class IOperationValidationContext { virtual HalVersion getHalVersion() const = 0; virtual uint32_t getNumInputs() const = 0; - virtual hal::OperandType getInputType(uint32_t index) const = 0; + virtual OperandType getInputType(uint32_t index) const = 0; virtual Shape getInputShape(uint32_t index) const = 0; - virtual const hal::OperandExtraParams getInputExtraParams(uint32_t index) const = 0; + virtual const Operand::ExtraParams& getInputExtraParams(uint32_t index) const = 0; virtual uint32_t getNumOutputs() const = 0; - virtual hal::OperandType getOutputType(uint32_t index) const = 0; + virtual OperandType getOutputType(uint32_t index) const = 0; virtual Shape getOutputShape(uint32_t index) const = 0; }; @@ -91,13 +92,13 @@ class IOperationExecutionContext { virtual ~IOperationExecutionContext() {} virtual uint32_t getNumInputs() const = 0; - virtual hal::OperandType getInputType(uint32_t index) const = 0; + virtual OperandType getInputType(uint32_t index) const = 0; virtual Shape getInputShape(uint32_t index) const = 0; virtual const void* getInputBuffer(uint32_t index) const = 0; - virtual const hal::OperandExtraParams getInputExtraParams(uint32_t index) const = 0; + virtual const Operand::ExtraParams& getInputExtraParams(uint32_t index) const = 0; virtual uint32_t getNumOutputs() const = 0; - virtual hal::OperandType getOutputType(uint32_t index) const = 0; + virtual OperandType getOutputType(uint32_t index) const = 0; virtual Shape getOutputShape(uint32_t index) const = 0; virtual void* getOutputBuffer(uint32_t index) = 0; @@ -125,11 +126,11 @@ class IOperationExecutionContext { // Verifies that the number and types of operation inputs are as expected. bool validateInputTypes(const IOperationValidationContext* context, - const std::vector<hal::OperandType>& expectedTypes); + const std::vector<OperandType>& expectedTypes); // Verifies that the number and types of operation outputs are as expected. bool validateOutputTypes(const IOperationValidationContext* context, - const std::vector<hal::OperandType>& expectedTypes); + const std::vector<OperandType>& expectedTypes); // Verifies that the HAL version specified in the context is greater or equal // than the minimal supported HAL version. diff --git a/nn/common/include/Utils.h b/nn/common/include/Utils.h index a2919091a..1d4c6811c 100644 --- a/nn/common/include/Utils.h +++ b/nn/common/include/Utils.h @@ -28,6 +28,8 @@ #include "HalInterfaces.h" #include "NeuralNetworks.h" #include "ValidateHal.h" +#include "nnapi/TypeUtils.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -135,24 +137,36 @@ void initVLogMask(); #define NN_RET_CHECK_GE(x, y) NN_RET_CHECK_OP(x, y, >=) #define NN_RET_CHECK_GT(x, y) NN_RET_CHECK_OP(x, y, >) +// Make an TimeoutDuration from a duration in nanoseconds. If the value exceeds +// the max duration, return the maximum expressible duration. +TimeoutDuration makeTimeoutDuration(uint64_t nanoseconds); + // Type to represent a deadline time point across processes. using Deadline = std::chrono::steady_clock::time_point; // Make an Deadline from a duration. If the sum of the current time and the // duration exceeds the max time, return a time point holding the maximum // expressible time. -Deadline makeDeadline(uint64_t duration); +Deadline makeDeadline(TimeoutDuration duration); +inline Deadline makeDeadline(uint64_t duration) { + return makeDeadline(makeTimeoutDuration(duration)); +} // Convenience function. If the duration is provided, this function creates a // Deadline using makeDeadline. If the duration is not provided, this function // returns std::nullopt. -std::optional<Deadline> makeDeadline(std::optional<uint64_t> duration); +inline std::optional<Deadline> makeDeadline(OptionalTimeoutDuration duration) { + return duration.has_value() ? makeDeadline(*duration) : std::optional<Deadline>{}; +} +inline std::optional<Deadline> makeDeadline(std::optional<uint64_t> duration) { + return duration.has_value() ? makeDeadline(*duration) : std::optional<Deadline>{}; +} // Make an optional Deadline from an OptionalTimePoint. If // timePoint.nanosecondsSinceEpoch cannot be represented in Deadline, return a // time point holding the maximum Deadline. If the OptionalTimePoint is none, // this function returns std::nullopt. -std::optional<Deadline> makeDeadline(const hal::OptionalTimePoint& timePoint); +std::optional<Deadline> makeDeadline(const V1_3::OptionalTimePoint& timePoint); // Returns true if the deadline has passed. Returns false if either the deadline // has not been exceeded or if the deadline is not present. @@ -160,7 +174,7 @@ bool hasDeadlinePassed(const std::optional<Deadline>& deadline); // Make an OptionalTimePoint from an optional Deadline. If the Deadline is not // provided, this function returns none for OptionalTimePoint. -hal::OptionalTimePoint makeTimePoint(const std::optional<Deadline>& deadline); +OptionalTimePoint makeTimePoint(const std::optional<Deadline>& deadline); // Ensure that every user of FalseyErrorStream is linked to the // correct instance, using the correct LOG_TAG @@ -193,14 +207,14 @@ struct VersionedType {}; template <> struct VersionedType<HalVersion::V1_2> { - using OperandPerformance = hal::V1_2::Capabilities::OperandPerformance; - using OperandType = hal::V1_2::OperandType; + using OperandPerformance = V1_2::Capabilities::OperandPerformance; + using OperandType = V1_2::OperandType; }; template <> struct VersionedType<HalVersion::V1_3> { - using OperandPerformance = hal::V1_3::Capabilities::OperandPerformance; - using OperandType = hal::V1_3::OperandType; + using OperandPerformance = V1_3::Capabilities::OperandPerformance; + using OperandType = V1_3::OperandType; }; template <HalVersion version> @@ -218,32 +232,32 @@ using VersionedOperandType = typename VersionedType<version>::OperandType; // separately using Capabilities::ifPerformance and // Capabilities::whilePerformance. template <HalVersion version> -hal::hidl_vec<VersionedOperandPerformance<version>> nonExtensionOperandPerformance( - hal::PerformanceInfo perf); +hardware::hidl_vec<VersionedOperandPerformance<version>> nonExtensionOperandPerformance( + V1_0::PerformanceInfo perf); // Update the vector entry corresponding to the specified OperandType with the // specified PerformanceInfo value. The vector must already have an entry for // that OperandType, and must be sorted by OperandType. -void update(hal::hidl_vec<hal::V1_2::Capabilities::OperandPerformance>* operandPerformance, - hal::V1_2::OperandType type, hal::PerformanceInfo perf); -void update(hal::hidl_vec<hal::V1_3::Capabilities::OperandPerformance>* operandPerformance, - hal::V1_3::OperandType type, hal::PerformanceInfo perf); +void update(hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>* operandPerformance, + V1_2::OperandType type, V1_0::PerformanceInfo perf); +void update(hardware::hidl_vec<V1_3::Capabilities::OperandPerformance>* operandPerformance, + V1_3::OperandType type, V1_0::PerformanceInfo perf); // Look for a vector entry corresponding to the specified OperandType. If // found, return the associated PerformanceInfo. If not, return a pessimistic // PerformanceInfo (FLT_MAX). The vector must be sorted by OperandType. -hal::PerformanceInfo lookup( - const hal::hidl_vec<hal::V1_2::Capabilities::OperandPerformance>& operandPerformance, - hal::V1_2::OperandType type); -hal::PerformanceInfo lookup( - const hal::hidl_vec<hal::V1_3::Capabilities::OperandPerformance>& operandPerformance, - hal::V1_3::OperandType type); +V1_0::PerformanceInfo lookup( + const hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>& operandPerformance, + V1_2::OperandType type); +V1_0::PerformanceInfo lookup( + const hardware::hidl_vec<V1_3::Capabilities::OperandPerformance>& operandPerformance, + V1_3::OperandType type); // Returns true if an operand type is an extension type. -bool isExtensionOperandType(hal::OperandType type); +bool isExtensionOperandType(V1_3::OperandType type); // Returns true if an operation type is an extension type. -bool isExtensionOperationType(hal::OperationType type); +bool isExtensionOperationType(V1_3::OperationType type); // Returns the amount of space needed to store a value of the specified // dimensions and type. For a tensor with unspecified rank or at least one @@ -253,8 +267,9 @@ bool isExtensionOperationType(hal::OperationType type); // Aborts if the size would overflow the return type. // // See also TypeManager::getSizeOfData(OperandType, const std::vector<uint32_t>&). -uint32_t nonExtensionOperandSizeOfData(hal::OperandType type, +uint32_t nonExtensionOperandSizeOfData(V1_3::OperandType type, const std::vector<uint32_t>& dimensions); +uint32_t nonExtensionOperandSizeOfData(OperandType type, const std::vector<uint32_t>& dimensions); // Returns the amount of space needed to store a value of the dimensions and // type of this operand. For a tensor with unspecified rank or at least one @@ -264,7 +279,10 @@ uint32_t nonExtensionOperandSizeOfData(hal::OperandType type, // Aborts if the size would overflow the return type. // // See also TypeManager::getSizeOfData(const Operand&). -inline uint32_t nonExtensionOperandSizeOfData(const hal::Operand& operand) { +inline uint32_t nonExtensionOperandSizeOfData(const Operand& operand) { + return nonExtensionOperandSizeOfData(operand.type, operand.dimensions); +} +inline uint32_t nonExtensionOperandSizeOfData(const V1_3::Operand& operand) { return nonExtensionOperandSizeOfData(operand.type, operand.dimensions); } @@ -283,7 +301,9 @@ uint32_t sizeOfTensorData(uint32_t sizeOfElement, const std::vector<uint32_t>& d // Aborts if the specified type is an extension type. // // See also TypeManager::sizeOfDataOverflowsUInt32(OperandType, const std::vector<uint32_t>&). -bool nonExtensionOperandSizeOfDataOverflowsUInt32(hal::OperandType type, +bool nonExtensionOperandSizeOfDataOverflowsUInt32(OperandType type, + const std::vector<uint32_t>& dimensions); +bool nonExtensionOperandSizeOfDataOverflowsUInt32(V1_3::OperandType type, const std::vector<uint32_t>& dimensions); // Returns true if the amount of space needed to store a value of the specified @@ -300,17 +320,21 @@ bool sizeOfTensorDataOverflowsUInt32(uint32_t elementSize, const std::vector<uin bool nonExtensionOperandTypeIsScalar(int type); // Returns the name of the operation type in ASCII. -std::string getOperationName(hal::OperationType opCode); +std::string getOperationName(V1_3::OperationType opCode); // Returns the name of the operand type in ASCII. -std::string getOperandTypeName(hal::OperandType type); +std::string getOperandTypeName(V1_3::OperandType type); // Whether an operand of tensor type has unspecified dimensions. // // Undefined behavior if the operand type is a scalar type. bool tensorHasUnspecifiedDimensions(int type, const uint32_t* dim, uint32_t dimCount); -bool tensorHasUnspecifiedDimensions(hal::OperandType type, const std::vector<uint32_t>& dimensions); -bool tensorHasUnspecifiedDimensions(const hal::Operand& operand); +bool tensorHasUnspecifiedDimensions(V1_3::OperandType type, + const std::vector<uint32_t>& dimensions); +bool tensorHasUnspecifiedDimensions(OperandType type, const std::vector<uint32_t>& dimensions); +bool tensorHasUnspecifiedDimensions(OperandType type, const Dimensions& dimensions); +bool tensorHasUnspecifiedDimensions(const Operand& operand); +bool tensorHasUnspecifiedDimensions(const V1_3::Operand& operand); bool tensorHasUnspecifiedDimensions(const ANeuralNetworksOperandType* type); // Returns the number of padding bytes needed to align data of the @@ -323,10 +347,11 @@ bool tensorHasUnspecifiedDimensions(const ANeuralNetworksOperandType* type); uint32_t alignBytesNeeded(uint32_t index, size_t length); // Does a detailed LOG(INFO) of the model -void logModelToInfo(const hal::V1_0::Model& model); -void logModelToInfo(const hal::V1_1::Model& model); -void logModelToInfo(const hal::V1_2::Model& model); -void logModelToInfo(const hal::V1_3::Model& model); +void logModelToInfo(const V1_0::Model& model); +void logModelToInfo(const V1_1::Model& model); +void logModelToInfo(const V1_2::Model& model); +void logModelToInfo(const V1_3::Model& model); +void logModelToInfo(const Model& model); inline std::string toString(uint32_t obj) { return std::to_string(obj); @@ -344,22 +369,22 @@ std::string toString(const std::vector<Type>& range) { template <typename A, typename B> std::string toString(const std::pair<A, B>& pair) { std::ostringstream oss; - oss << "(" << toString(pair.first) << ", " << toString(pair.second) << ")"; + oss << "(" << pair.first << ", " << pair.second << ")"; return oss.str(); } -inline std::string toString(HalVersion halVersion) { +inline std::ostream& operator<<(std::ostream& os, const HalVersion& halVersion) { switch (halVersion) { case HalVersion::UNKNOWN: - return "UNKNOWN HAL version"; + return os << "UNKNOWN HAL version"; case HalVersion::V1_0: - return "HAL version 1.0"; + return os << "HAL version 1.0"; case HalVersion::V1_1: - return "HAL version 1.1"; + return os << "HAL version 1.1"; case HalVersion::V1_2: - return "HAL version 1.2"; + return os << "HAL version 1.2"; case HalVersion::V1_3: - return "HAL version 1.3"; + return os << "HAL version 1.3"; } } @@ -368,7 +393,7 @@ inline bool validCode(uint32_t codeCount, uint32_t codeCountOEM, uint32_t code) } bool validateOperandSymmPerChannelQuantParams( - const hal::Operand& halOperand, + const V1_3::Operand& halOperand, const ANeuralNetworksSymmPerChannelQuantParams& channelQuant, const char* tag); // Validates an operand type. @@ -376,25 +401,24 @@ bool validateOperandSymmPerChannelQuantParams( // extensionOperandTypeInfo must be nullptr iff the type is not an extension type. // // If allowPartial is true, the dimensions may be underspecified. -int validateOperandType( - const ANeuralNetworksOperandType& type, - const hal::Extension::OperandTypeInformation* const extensionOperandTypeInfo, - const char* tag, bool allowPartial); +int validateOperandType(const ANeuralNetworksOperandType& type, + const Extension::OperandTypeInformation* const extensionOperandTypeInfo, + const char* tag, bool allowPartial); int validateOperandList(uint32_t count, const uint32_t* list, uint32_t operandCount, const char* tag); // A set of functions to help validate models containing IF or WHILE operations. struct SubgraphValidationHelper { // Checks if a given operand is a SUBGRAPH operand with a valid offset. - std::function<bool(const hal::Operand&)> isValidSubgraphReference; + std::function<bool(const Operand&)> isValidSubgraphReference; // Gets the input count of a subgraph referenced by a given operand. - std::function<uint32_t(const hal::Operand&)> getSubgraphInputCount; + std::function<uint32_t(const Operand&)> getSubgraphInputCount; // Gets the output count of a subgraph referenced by a given operand. - std::function<uint32_t(const hal::Operand&)> getSubgraphOutputCount; + std::function<uint32_t(const Operand&)> getSubgraphOutputCount; // Gets the specified input operand of a subgraph referenced by a given operand. - std::function<const hal::Operand*(const hal::Operand&, uint32_t)> getSubgraphInputOperand; + std::function<const Operand*(const Operand&, uint32_t)> getSubgraphInputOperand; // Gets the specified output operand of a subgraph referenced by a given operand. - std::function<const hal::Operand*(const hal::Operand&, uint32_t)> getSubgraphOutputOperand; + std::function<const Operand*(const Operand&, uint32_t)> getSubgraphOutputOperand; // Whether control flow operations with inner or outer input or output // operands of unknown size are allowed. bool allowControlFlowOperationWithOperandOfUnknownSize; @@ -405,7 +429,7 @@ struct SubgraphValidationHelper { // The last argument is only used for validating IF and WHILE operations. int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount, const uint32_t* inputIndexes, uint32_t outputCount, - const uint32_t* outputIndexes, const std::vector<hal::Operand>& operands, + const uint32_t* outputIndexes, const std::vector<Operand>& operands, HalVersion halVersion, const SubgraphValidationHelper& helper); inline size_t getSizeFromInts(int lower, int higher) { @@ -414,40 +438,41 @@ inline size_t getSizeFromInts(int lower, int higher) { // Convert ANEURALNETWORKS_* result code to ErrorStatus. // Not guaranteed to be a 1-to-1 mapping. -hal::ErrorStatus convertResultCodeToErrorStatus(int resultCode); +ErrorStatus convertResultCodeToErrorStatus(int resultCode); +V1_3::ErrorStatus convertResultCodeToHalErrorStatus(int resultCode); // Convert ErrorStatus to ANEURALNETWORKS_* result code. // Not guaranteed to be a 1-to-1 mapping. -int convertErrorStatusToResultCode(hal::ErrorStatus status); +int convertErrorStatusToResultCode(ErrorStatus status); +int convertErrorStatusToResultCode(V1_3::ErrorStatus status); // Convert execution results to runtime format. Additionally checks that the // returned results abide by the HAL specification, and logs an error if the // result violates the specification. -std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> getExecutionResult( - hal::ErrorStatus status, std::vector<hal::OutputShape> outputShapes, hal::Timing timing); - -// Combine two tensor dimensions, both may have unspecified dimensions or rank. -std::optional<std::vector<uint32_t>> combineDimensions(const std::vector<uint32_t>& lhs, - const std::vector<uint32_t>& rhs); +std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult( + V1_3::ErrorStatus status, const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing); +std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult( + ErrorStatus status, std::vector<OutputShape> outputShapes, Timing timing); // Versioning -bool compliantWithV1_0(const hal::V1_0::Capabilities& capabilities); -bool compliantWithV1_0(const hal::V1_1::Capabilities& capabilities); -bool compliantWithV1_0(const hal::V1_2::Capabilities& capabilities); -bool compliantWithV1_0(const hal::V1_3::Capabilities& capabilities); -bool compliantWithV1_1(const hal::V1_0::Capabilities& capabilities); -bool compliantWithV1_1(const hal::V1_1::Capabilities& capabilities); -bool compliantWithV1_1(const hal::V1_2::Capabilities& capabilities); -bool compliantWithV1_1(const hal::V1_3::Capabilities& capabilities); -bool compliantWithV1_2(const hal::V1_0::Capabilities& capabilities); -bool compliantWithV1_2(const hal::V1_1::Capabilities& capabilities); -bool compliantWithV1_2(const hal::V1_2::Capabilities& capabilities); -bool compliantWithV1_2(const hal::V1_3::Capabilities& capabilities); -bool compliantWithV1_3(const hal::V1_0::Capabilities& capabilities); -bool compliantWithV1_3(const hal::V1_1::Capabilities& capabilities); -bool compliantWithV1_3(const hal::V1_2::Capabilities& capabilities); -bool compliantWithV1_3(const hal::V1_3::Capabilities& capabilities); +bool compliantWithV1_0(const V1_0::Capabilities& capabilities); +bool compliantWithV1_0(const V1_1::Capabilities& capabilities); +bool compliantWithV1_0(const V1_2::Capabilities& capabilities); +bool compliantWithV1_0(const V1_3::Capabilities& capabilities); +bool compliantWithV1_1(const V1_0::Capabilities& capabilities); +bool compliantWithV1_1(const V1_1::Capabilities& capabilities); +bool compliantWithV1_1(const V1_2::Capabilities& capabilities); +bool compliantWithV1_1(const V1_3::Capabilities& capabilities); +bool compliantWithV1_2(const V1_0::Capabilities& capabilities); +bool compliantWithV1_2(const V1_1::Capabilities& capabilities); +bool compliantWithV1_2(const V1_2::Capabilities& capabilities); +bool compliantWithV1_2(const V1_3::Capabilities& capabilities); +bool compliantWithV1_3(const V1_0::Capabilities& capabilities); +bool compliantWithV1_3(const V1_1::Capabilities& capabilities); +bool compliantWithV1_3(const V1_2::Capabilities& capabilities); +bool compliantWithV1_3(const V1_3::Capabilities& capabilities); // If noncompliantOperations != nullptr, then // precondition: noncompliantOperations->empty() @@ -455,114 +480,127 @@ bool compliantWithV1_3(const hal::V1_3::Capabilities& capabilities); // operations; if the compliance check fails for some reason // other than a noncompliant operation, // *noncompliantOperations consists of the indices of all operations -bool compliantWithV1_0(const hal::V1_0::Model& model); -bool compliantWithV1_0(const hal::V1_1::Model& model); -bool compliantWithV1_0(const hal::V1_2::Model& model, +bool compliantWithV1_0(const V1_0::Model& model); +bool compliantWithV1_0(const V1_1::Model& model); +bool compliantWithV1_0(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations = nullptr); -bool compliantWithV1_0(const hal::V1_3::Model& model, +bool compliantWithV1_0(const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations = nullptr); -bool compliantWithV1_1(const hal::V1_0::Model& model); -bool compliantWithV1_1(const hal::V1_1::Model& model); -bool compliantWithV1_1(const hal::V1_2::Model& model, +bool compliantWithV1_1(const V1_0::Model& model); +bool compliantWithV1_1(const V1_1::Model& model); +bool compliantWithV1_1(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations = nullptr); -bool compliantWithV1_1(const hal::V1_3::Model& model, +bool compliantWithV1_1(const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations = nullptr); -bool compliantWithV1_2(const hal::V1_0::Model& model); -bool compliantWithV1_2(const hal::V1_1::Model& model); -bool compliantWithV1_2(const hal::V1_2::Model& model, +bool compliantWithV1_2(const V1_0::Model& model); +bool compliantWithV1_2(const V1_1::Model& model); +bool compliantWithV1_2(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations = nullptr); -bool compliantWithV1_2(const hal::V1_3::Model& model, +bool compliantWithV1_2(const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations = nullptr); -hal::V1_0::ErrorStatus convertToV1_0(hal::V1_0::ErrorStatus status); -hal::V1_0::ErrorStatus convertToV1_0(hal::V1_3::ErrorStatus status); -hal::V1_3::ErrorStatus convertToV1_3(hal::V1_0::ErrorStatus status); -hal::V1_3::ErrorStatus convertToV1_3(hal::V1_3::ErrorStatus status); - -hal::V1_0::Capabilities convertToV1_0(const hal::V1_0::Capabilities& capabilities); -hal::V1_0::Capabilities convertToV1_0(const hal::V1_1::Capabilities& capabilities); -hal::V1_0::Capabilities convertToV1_0(const hal::V1_2::Capabilities& capabilities); -hal::V1_0::Capabilities convertToV1_0(const hal::V1_3::Capabilities& capabilities); -hal::V1_1::Capabilities convertToV1_1(const hal::V1_0::Capabilities& capabilities); -hal::V1_1::Capabilities convertToV1_1(const hal::V1_1::Capabilities& capabilities); -hal::V1_1::Capabilities convertToV1_1(const hal::V1_2::Capabilities& capabilities); -hal::V1_1::Capabilities convertToV1_1(const hal::V1_3::Capabilities& capabilities); -hal::V1_2::Capabilities convertToV1_2(const hal::V1_0::Capabilities& capabilities); -hal::V1_2::Capabilities convertToV1_2(const hal::V1_1::Capabilities& capabilities); -hal::V1_2::Capabilities convertToV1_2(const hal::V1_2::Capabilities& capabilities); -hal::V1_2::Capabilities convertToV1_2(const hal::V1_3::Capabilities& capabilities); -hal::V1_3::Capabilities convertToV1_3(const hal::V1_0::Capabilities& capabilities); -hal::V1_3::Capabilities convertToV1_3(const hal::V1_1::Capabilities& capabilities); -hal::V1_3::Capabilities convertToV1_3(const hal::V1_2::Capabilities& capabilities); -hal::V1_3::Capabilities convertToV1_3(const hal::V1_3::Capabilities& capabilities); - -hal::V1_0::Model convertToV1_0(const hal::V1_0::Model& model); -hal::V1_0::Model convertToV1_0(const hal::V1_1::Model& model); -hal::V1_0::Model convertToV1_0(const hal::V1_2::Model& model); -hal::V1_0::Model convertToV1_0(const hal::V1_3::Model& model); -hal::V1_1::Model convertToV1_1(const hal::V1_0::Model& model); -hal::V1_1::Model convertToV1_1(const hal::V1_1::Model& model); -hal::V1_1::Model convertToV1_1(const hal::V1_2::Model& model); -hal::V1_1::Model convertToV1_1(const hal::V1_3::Model& model); -hal::V1_2::Model convertToV1_2(const hal::V1_0::Model& model); -hal::V1_2::Model convertToV1_2(const hal::V1_1::Model& model); -hal::V1_2::Model convertToV1_2(const hal::V1_2::Model& model); -hal::V1_2::Model convertToV1_2(const hal::V1_3::Model& model); -hal::V1_3::Model convertToV1_3(const hal::V1_0::Model& model); -hal::V1_3::Model convertToV1_3(const hal::V1_1::Model& model); -hal::V1_3::Model convertToV1_3(const hal::V1_2::Model& model); -hal::V1_3::Model convertToV1_3(const hal::V1_3::Model& model); - -hal::V1_0::OperationType uncheckedConvertToV1_0(hal::V1_3::OperationType type); -hal::V1_1::OperationType uncheckedConvertToV1_1(hal::V1_3::OperationType type); -hal::V1_2::OperationType uncheckedConvertToV1_2(hal::V1_3::OperationType type); - -hal::V1_0::Operand convertToV1_0(const hal::V1_2::Operand& operand); -hal::V1_0::Operand convertToV1_0(const hal::V1_3::Operand& operand); -hal::V1_2::Operand convertToV1_2(const hal::V1_0::Operand& operand); -hal::V1_2::Operand convertToV1_2(const hal::V1_3::Operand& operand); -hal::V1_3::Operand convertToV1_3(const hal::V1_0::Operand& operand); -hal::V1_3::Operand convertToV1_3(const hal::V1_2::Operand& operand); -hal::V1_3::Operand convertToV1_3(const hal::V1_3::Operand& operand); - -hal::hidl_vec<hal::V1_0::Operand> convertToV1_0(const hal::hidl_vec<hal::V1_0::Operand>& operands); -hal::hidl_vec<hal::V1_0::Operand> convertToV1_0(const hal::hidl_vec<hal::V1_2::Operand>& operands); -hal::hidl_vec<hal::V1_0::Operand> convertToV1_0(const hal::hidl_vec<hal::V1_3::Operand>& operands); -hal::hidl_vec<hal::V1_2::Operand> convertToV1_2(const hal::hidl_vec<hal::V1_0::Operand>& operands); -hal::hidl_vec<hal::V1_2::Operand> convertToV1_2(const hal::hidl_vec<hal::V1_2::Operand>& operands); -hal::hidl_vec<hal::V1_2::Operand> convertToV1_2(const hal::hidl_vec<hal::V1_3::Operand>& operands); -hal::hidl_vec<hal::V1_3::Operand> convertToV1_3(const hal::hidl_vec<hal::V1_0::Operand>& operands); -hal::hidl_vec<hal::V1_3::Operand> convertToV1_3(const hal::hidl_vec<hal::V1_2::Operand>& operands); -hal::hidl_vec<hal::V1_3::Operand> convertToV1_3(const hal::hidl_vec<hal::V1_3::Operand>& operands); - -bool compliantWithV1_0(const hal::V1_0::Request& request); -bool compliantWithV1_0(const hal::V1_3::Request& request); -bool compliantWithV1_2(const hal::V1_3::Request& request); - -hal::V1_0::Request convertToV1_0(const hal::V1_0::Request& request); -hal::V1_0::Request convertToV1_0(const hal::V1_3::Request& request); -hal::V1_0::Request convertToV1_2(const hal::V1_3::Request& request); -hal::V1_3::Request convertToV1_3(const hal::V1_0::Request& request); -hal::V1_3::Request convertToV1_3(const hal::V1_3::Request& request); - -bool compliantWithV1_0(hal::V1_0::OperandLifeTime lifetime); -bool compliantWithV1_0(hal::V1_3::OperandLifeTime lifetime); -bool compliantWithV1_3(hal::V1_0::OperandLifeTime lifetime); -bool compliantWithV1_3(hal::V1_3::OperandLifeTime lifetime); - -hal::V1_0::OperandLifeTime convertToV1_0(hal::V1_0::OperandLifeTime lifetime); -hal::V1_0::OperandLifeTime convertToV1_0(hal::V1_3::OperandLifeTime lifetime); -hal::V1_3::OperandLifeTime convertToV1_3(hal::V1_0::OperandLifeTime lifetime); -hal::V1_3::OperandLifeTime convertToV1_3(hal::V1_3::OperandLifeTime lifetime); - -constexpr hal::Priority convertToHalPriority(int32_t priority) { +V1_0::ErrorStatus convertToV1_0(V1_0::ErrorStatus status); +V1_0::ErrorStatus convertToV1_0(V1_3::ErrorStatus status); +V1_3::ErrorStatus convertToV1_3(V1_0::ErrorStatus status); +V1_3::ErrorStatus convertToV1_3(V1_3::ErrorStatus status); + +V1_0::Capabilities convertToV1_0(const V1_0::Capabilities& capabilities); +V1_0::Capabilities convertToV1_0(const V1_1::Capabilities& capabilities); +V1_0::Capabilities convertToV1_0(const V1_2::Capabilities& capabilities); +V1_0::Capabilities convertToV1_0(const V1_3::Capabilities& capabilities); +V1_1::Capabilities convertToV1_1(const V1_0::Capabilities& capabilities); +V1_1::Capabilities convertToV1_1(const V1_1::Capabilities& capabilities); +V1_1::Capabilities convertToV1_1(const V1_2::Capabilities& capabilities); +V1_1::Capabilities convertToV1_1(const V1_3::Capabilities& capabilities); +V1_2::Capabilities convertToV1_2(const V1_0::Capabilities& capabilities); +V1_2::Capabilities convertToV1_2(const V1_1::Capabilities& capabilities); +V1_2::Capabilities convertToV1_2(const V1_2::Capabilities& capabilities); +V1_2::Capabilities convertToV1_2(const V1_3::Capabilities& capabilities); +V1_3::Capabilities convertToV1_3(const V1_0::Capabilities& capabilities); +V1_3::Capabilities convertToV1_3(const V1_1::Capabilities& capabilities); +V1_3::Capabilities convertToV1_3(const V1_2::Capabilities& capabilities); +V1_3::Capabilities convertToV1_3(const V1_3::Capabilities& capabilities); + +V1_0::Model convertToV1_0(const V1_0::Model& model); +V1_0::Model convertToV1_0(const V1_1::Model& model); +V1_0::Model convertToV1_0(const V1_2::Model& model); +V1_0::Model convertToV1_0(const V1_3::Model& model); +V1_1::Model convertToV1_1(const V1_0::Model& model); +V1_1::Model convertToV1_1(const V1_1::Model& model); +V1_1::Model convertToV1_1(const V1_2::Model& model); +V1_1::Model convertToV1_1(const V1_3::Model& model); +V1_2::Model convertToV1_2(const V1_0::Model& model); +V1_2::Model convertToV1_2(const V1_1::Model& model); +V1_2::Model convertToV1_2(const V1_2::Model& model); +V1_2::Model convertToV1_2(const V1_3::Model& model); +V1_3::Model convertToV1_3(const V1_0::Model& model); +V1_3::Model convertToV1_3(const V1_1::Model& model); +V1_3::Model convertToV1_3(const V1_2::Model& model); +V1_3::Model convertToV1_3(const V1_3::Model& model); + +V1_0::OperationType uncheckedConvertToV1_0(V1_3::OperationType type); +V1_1::OperationType uncheckedConvertToV1_1(V1_3::OperationType type); +V1_2::OperationType uncheckedConvertToV1_2(V1_3::OperationType type); + +V1_0::Operand convertToV1_0(const V1_2::Operand& operand); +V1_0::Operand convertToV1_0(const V1_3::Operand& operand); +V1_2::Operand convertToV1_2(const V1_0::Operand& operand); +V1_2::Operand convertToV1_2(const V1_3::Operand& operand); +V1_3::Operand convertToV1_3(const V1_0::Operand& operand); +V1_3::Operand convertToV1_3(const V1_2::Operand& operand); +V1_3::Operand convertToV1_3(const V1_3::Operand& operand); + +hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_0::Operand>& operands); +hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_2::Operand>& operands); +hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_3::Operand>& operands); +hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_0::Operand>& operands); +hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_2::Operand>& operands); +hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_3::Operand>& operands); +hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_0::Operand>& operands); +hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_2::Operand>& operands); +hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_3::Operand>& operands); + +bool compliantWithV1_0(const V1_0::Request& request); +bool compliantWithV1_0(const V1_3::Request& request); +bool compliantWithV1_2(const V1_3::Request& request); + +V1_0::Request convertToV1_0(const V1_0::Request& request); +V1_0::Request convertToV1_0(const V1_3::Request& request); +V1_0::Request convertToV1_2(const V1_3::Request& request); +V1_3::Request convertToV1_3(const V1_0::Request& request); +V1_3::Request convertToV1_3(const V1_3::Request& request); + +bool compliantWithV1_0(V1_0::OperandLifeTime lifetime); +bool compliantWithV1_0(V1_3::OperandLifeTime lifetime); +bool compliantWithV1_3(V1_0::OperandLifeTime lifetime); +bool compliantWithV1_3(V1_3::OperandLifeTime lifetime); + +V1_0::OperandLifeTime convertToV1_0(V1_0::OperandLifeTime lifetime); +V1_0::OperandLifeTime convertToV1_0(V1_3::OperandLifeTime lifetime); +V1_3::OperandLifeTime convertToV1_3(V1_0::OperandLifeTime lifetime); +V1_3::OperandLifeTime convertToV1_3(V1_3::OperandLifeTime lifetime); + +constexpr V1_3::Priority convertToHalPriority(int32_t priority) { + switch (priority) { + case ANEURALNETWORKS_PRIORITY_LOW: + return V1_3::Priority::LOW; + case ANEURALNETWORKS_PRIORITY_MEDIUM: + return V1_3::Priority::MEDIUM; + case ANEURALNETWORKS_PRIORITY_HIGH: + return V1_3::Priority::HIGH; + } + LOG(FATAL) << "unrecognized priority: " << priority; + return {}; +} + +constexpr Priority convertToCanonicalPriority(int32_t priority) { switch (priority) { case ANEURALNETWORKS_PRIORITY_LOW: - return hal::Priority::LOW; + return Priority::LOW; case ANEURALNETWORKS_PRIORITY_MEDIUM: - return hal::Priority::MEDIUM; + return Priority::MEDIUM; case ANEURALNETWORKS_PRIORITY_HIGH: - return hal::Priority::HIGH; + return Priority::HIGH; } LOG(FATAL) << "unrecognized priority: " << priority; return {}; @@ -583,6 +621,76 @@ FenceState syncWait(int fd, int timeout); uint32_t getProp(const char* str, uint32_t defaultValue = 0); #endif // NN_DEBUGGABLE +// DEPRECATED. Use checked conversions from nnapi/hal/1.X/Conversions.h. +Capabilities::OperandPerformance uncheckedConvert( + const V1_3::Capabilities::OperandPerformance& operandPerformance); +Capabilities::PerformanceInfo uncheckedConvert(const V1_0::PerformanceInfo& performanceInfo); +Capabilities uncheckedConvert(const V1_3::Capabilities& capabilities); +DataLocation uncheckedConvert(const V1_0::DataLocation& location); +ErrorStatus uncheckedConvert(V1_0::ErrorStatus status); +ErrorStatus uncheckedConvert(V1_3::ErrorStatus status); +Extension::OperandTypeInformation uncheckedConvert(const V1_2::Extension::OperandTypeInformation&); +Extension uncheckedConvert(const V1_2::Extension& extension); +hardware::hidl_vec<uint8_t> uncheckedConvert(const Operand::ExtensionParams& params); +MeasureTiming uncheckedConvert(V1_2::MeasureTiming measure); +Memory uncheckedConvert(const hardware::hidl_memory& memory); +Model::ExtensionNameAndPrefix uncheckedConvert(const V1_2::Model::ExtensionNameAndPrefix&); +Model::Subgraph uncheckedConvert(const V1_3::Subgraph& subgraph); +Model uncheckedConvert(const V1_3::Model& model); +Operand::ExtensionParams uncheckedConvert(const hardware::hidl_vec<uint8_t>& params); +Operand::ExtraParams uncheckedConvert(const V1_2::Operand::ExtraParams& params); +Operand::LifeTime uncheckedConvert(V1_3::OperandLifeTime lifetime); +Operand::SymmPerChannelQuantParams uncheckedConvert(const V1_2::SymmPerChannelQuantParams& params); +OperandType uncheckedConvert(V1_3::OperandType operandType); +Operand uncheckedConvert(const V1_3::Operand& operand); +OperationType uncheckedConvert(V1_3::OperationType operationType); +Operation uncheckedConvert(const V1_3::Operation& operation); +OptionalTimeoutDuration uncheckedConvert(const V1_3::OptionalTimeoutDuration& timeoutDuration); +OutputShape uncheckedConvert(const V1_2::OutputShape& outputShape); +Request::Argument uncheckedConvert(const V1_0::RequestArgument& requestArgument); +Request::MemoryPool uncheckedConvert(const V1_3::Request::MemoryPool& memoryPool); +Request uncheckedConvert(const V1_3::Request& request); +std::vector<Extension> uncheckedConvert(const hardware::hidl_vec<V1_2::Extension>& extensions); +std::vector<Memory> uncheckedConvert(const hardware::hidl_vec<hardware::hidl_memory>& memories); +std::vector<Model::Subgraph> uncheckedConvert(const hardware::hidl_vec<V1_3::Subgraph>& subgraphs); +std::vector<Operand> uncheckedConvert(const hardware::hidl_vec<V1_3::Operand>& operands); +std::vector<OutputShape> uncheckedConvert( + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes); +std::vector<Request::MemoryPool> uncheckedConvert( + const hardware::hidl_vec<V1_3::Request::MemoryPool>& memoryPools); +Timing uncheckedConvert(const V1_2::Timing& timing); + +// DEPRECATED. Use conversions from nnapi/hal/1.X/Conversions.h. +hardware::hidl_memory convertToV1_0(const Memory& memory); +hardware::hidl_vec<hardware::hidl_memory> convertToV1_0(const std::vector<Memory>& memories); +hardware::hidl_vec<uint8_t> convertToV1_0(const Model::OperandValues& operandValues); +hardware::hidl_vec<V1_2::OutputShape> convertToV1_2(const std::vector<OutputShape>& outputShapes); +hardware::hidl_vec<V1_3::BufferRole> convertToV1_3(const std::vector<BufferRole>& bufferRoles); +V1_0::DataLocation convertToV1_0(const DataLocation& location); +V1_0::ErrorStatus convertToV1_0(ErrorStatus status); +V1_0::RequestArgument convertToV1_0(const Request::Argument& requestArgument); +V1_1::ExecutionPreference convertToV1_1(ExecutionPreference preference); +V1_2::MeasureTiming convertToV1_2(MeasureTiming measure); +V1_2::Model::ExtensionNameAndPrefix convertToV1_2(const Model::ExtensionNameAndPrefix&); +V1_2::Operand::ExtraParams convertToV1_2(const Operand::ExtraParams& params); +V1_2::OutputShape convertToV1_2(const OutputShape& outputShape); +V1_2::SymmPerChannelQuantParams convertToV1_2(const Operand::SymmPerChannelQuantParams& params); +V1_2::Timing convertToV1_2(const Timing& timing); +V1_3::BufferRole convertToV1_3(const BufferRole& bufferRole); +V1_3::ErrorStatus convertToV1_3(ErrorStatus status); +V1_3::Model convertToV1_3(const Model& model); +V1_3::Operand convertToV1_3(const Operand& operand); +V1_3::OperandLifeTime convertToV1_3(Operand::LifeTime lifetime); +V1_3::OperandType convertToV1_3(OperandType operandType); +V1_3::Operation convertToV1_3(const Operation& operation); +V1_3::OperationType convertToV1_3(OperationType operationType); +V1_3::OptionalTimeoutDuration convertToV1_3(const OptionalTimeoutDuration& timeoutDuration); +V1_3::OptionalTimePoint convertToV1_3(const OptionalTimePoint& timePoint); +V1_3::Priority convertToV1_3(Priority priority); +V1_3::Request convertToV1_3(const Request& request); +V1_3::Request::MemoryPool convertToV1_3(const Request::MemoryPool& memoryPool); +V1_3::Subgraph convertToV1_3(const Model::Subgraph& model); + } // namespace nn } // namespace android diff --git a/nn/common/include/ValidateHal.h b/nn/common/include/ValidateHal.h index 32d7662ed..c501fc011 100644 --- a/nn/common/include/ValidateHal.h +++ b/nn/common/include/ValidateHal.h @@ -35,7 +35,7 @@ enum class HalVersion : int32_t { }; enum class IOType { INPUT, OUTPUT }; -using PreparedModelRole = std::tuple<const hal::IPreparedModel*, IOType, uint32_t>; +using PreparedModelRole = std::tuple<const V1_3::IPreparedModel*, IOType, uint32_t>; // 1.3 HAL does not support control flow operations with operands of unknown size. // See http://b/132458982#comment63. @@ -62,35 +62,35 @@ bool validateRequest(const T_Request& request, const T_Model& model, bool allowUnspecifiedOutput = true); // Verifies that the execution preference is valid. -bool validateExecutionPreference(hal::ExecutionPreference preference); +bool validateExecutionPreference(V1_1::ExecutionPreference preference); // Verifies that the priority is valid. -bool validatePriority(hal::Priority priority); +bool validatePriority(V1_3::Priority priority); -bool validOperationType(hal::V1_0::OperationType operation); -bool validOperationType(hal::V1_1::OperationType operation); -bool validOperationType(hal::V1_2::OperationType operation); +bool validOperationType(V1_0::OperationType operation); +bool validOperationType(V1_1::OperationType operation); +bool validOperationType(V1_2::OperationType operation); -bool validOperandType(hal::V1_0::OperandType operand); -bool validOperandType(hal::V1_2::OperandType operand); -bool validOperandType(hal::V1_3::OperandType operand); +bool validOperandType(V1_0::OperandType operand); +bool validOperandType(V1_2::OperandType operand); +bool validOperandType(V1_3::OperandType operand); // Verifies that the memory pool is valid in the specified HAL version. -bool validatePool(const hal::hidl_memory& pool, HalVersion ver = HalVersion::LATEST); -bool validatePool(const hal::V1_3::Request::MemoryPool& pool, HalVersion ver = HalVersion::LATEST); +bool validatePool(const hardware::hidl_memory& pool, HalVersion ver = HalVersion::LATEST); +bool validatePool(const V1_3::Request::MemoryPool& pool, HalVersion ver = HalVersion::LATEST); // Verifies that the input arguments to IDevice::allocate are valid. // Optionally, this function can return a flattened prepared model roles and a combined operand. // Pass nullptr if either value is not needed. // IMPORTANT: This function cannot validate dimensions and extraParams with extension operand type. // Each driver should do their own validation of extension type dimensions and extraParams. -bool validateMemoryDesc( - const hal::V1_3::BufferDesc& desc, - const hal::hidl_vec<sp<hal::V1_3::IPreparedModel>>& preparedModels, - const hal::hidl_vec<hal::V1_3::BufferRole>& inputRoles, - const hal::hidl_vec<hal::V1_3::BufferRole>& outputRoles, - std::function<const hal::V1_3::Model*(const sp<hal::V1_3::IPreparedModel>&)> getModel, - std::set<PreparedModelRole>* preparedModelRoles, hal::V1_3::Operand* combinedOperand); +bool validateMemoryDesc(const V1_3::BufferDesc& desc, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, + const hardware::hidl_vec<V1_3::BufferRole>& inputRoles, + const hardware::hidl_vec<V1_3::BufferRole>& outputRoles, + std::function<const V1_3::Model*(const sp<V1_3::IPreparedModel>&)> getModel, + std::set<PreparedModelRole>* preparedModelRoles, + V1_3::Operand* combinedOperand); } // namespace nn } // namespace android diff --git a/nn/common/operations/Activation.cpp b/nn/common/operations/Activation.cpp index ff5a55dc3..c0a1934d7 100644 --- a/nn/common/operations/Activation.cpp +++ b/nn/common/operations/Activation.cpp @@ -28,7 +28,6 @@ #include "ActivationFunctor.h" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -36,8 +35,6 @@ namespace android { namespace nn { -using namespace hal; - namespace activation { constexpr uint32_t kNumInputs = 1; @@ -373,7 +370,7 @@ bool validate(OperationType opType, const IOperationValidationContext* context) } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { NN_RET_CHECK(validateHalVersion(context, HalVersion::V1_3)); } else { - NN_RET_CHECK_FAIL() << "Unsupported tensor type for operation " << getOperationName(opType); + NN_RET_CHECK_FAIL() << "Unsupported tensor type for operation " << opType; } const Shape& input = context->getInputShape(kInputTensor); if (hasKnownRank(input)) { diff --git a/nn/common/operations/ArgMinMax.cpp b/nn/common/operations/ArgMinMax.cpp index f53ba47e4..2ee413c7e 100644 --- a/nn/common/operations/ArgMinMax.cpp +++ b/nn/common/operations/ArgMinMax.cpp @@ -19,7 +19,6 @@ #define LOG_TAG "Operations" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "Operations.h" #include "Tracing.h" @@ -27,8 +26,6 @@ namespace android { namespace nn { -using namespace hal; - template <typename In, typename Out> static void argMinMaxImpl(const In* inputData, const Shape& inputShape, int32_t axis, bool isArgMin, Out* outputData, const Shape& outputShape) { diff --git a/nn/common/operations/BidirectionalSequenceLSTM.cpp b/nn/common/operations/BidirectionalSequenceLSTM.cpp index 12ac43f20..6cf095b1e 100644 --- a/nn/common/operations/BidirectionalSequenceLSTM.cpp +++ b/nn/common/operations/BidirectionalSequenceLSTM.cpp @@ -23,7 +23,6 @@ #include "CpuExecutor.h" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -32,8 +31,6 @@ namespace nn { namespace { -using namespace hal; - template <typename T> inline T* GetBuffer(RunTimeOperandInfo* operand) { return reinterpret_cast<T*>(operand->buffer); diff --git a/nn/common/operations/BidirectionalSequenceLSTM.h b/nn/common/operations/BidirectionalSequenceLSTM.h index 184b65da0..7077d3b10 100644 --- a/nn/common/operations/BidirectionalSequenceLSTM.h +++ b/nn/common/operations/BidirectionalSequenceLSTM.h @@ -34,12 +34,11 @@ struct RunTimeOperandInfo; class BidirectionalSequenceLSTM { public: - BidirectionalSequenceLSTM(const hal::Operation& operation, RunTimeOperandInfo* operands); + BidirectionalSequenceLSTM(const Operation& operation, RunTimeOperandInfo* operands); - bool Prepare(const hal::Operation& operation, RunTimeOperandInfo* operands, - Shape* fwOutputShape, Shape* bwOutputShape, Shape* fwOutputActivationState, - Shape* fwOutputCellState, Shape* bwOutputActivationState, - Shape* bwOutputCellState); + bool Prepare(const Operation& operation, RunTimeOperandInfo* operands, Shape* fwOutputShape, + Shape* bwOutputShape, Shape* fwOutputActivationState, Shape* fwOutputCellState, + Shape* bwOutputActivationState, Shape* bwOutputCellState); bool Eval(); // Input Tensors of size {max_time, n_batch, n_input} diff --git a/nn/common/operations/BidirectionalSequenceRNN.cpp b/nn/common/operations/BidirectionalSequenceRNN.cpp index 98917c0b8..adacea0c6 100644 --- a/nn/common/operations/BidirectionalSequenceRNN.cpp +++ b/nn/common/operations/BidirectionalSequenceRNN.cpp @@ -20,7 +20,6 @@ #include <utility> #include <vector> -#include "HalInterfaces.h" #include "OperationResolver.h" #include "RNN.h" @@ -61,8 +60,6 @@ constexpr uint32_t kBwOutputHiddenStateTensor = 3; namespace { -using namespace hal; - template <typename T> void transposeFirstTwoDims(const T* input, const Shape& inputShape, T* output) { const uint32_t firstDimSize = getSizeOfDimension(inputShape, 0); @@ -327,7 +324,7 @@ bool validate(const IOperationValidationContext* context) { OperandType inputType = context->getInputType(kInputTensor); if (inputType != OperandType::TENSOR_FLOAT16 && inputType != OperandType::TENSOR_FLOAT32) { LOG(ERROR) << "Unsupported input operand type for UNIDIRECTIONAL_SEQUENCE_RNN op: " - << toString(inputType); + << inputType; return false; } NN_RET_CHECK(validateInputTypes( diff --git a/nn/common/operations/Broadcast.cpp b/nn/common/operations/Broadcast.cpp index 17094afa3..67bb914bd 100644 --- a/nn/common/operations/Broadcast.cpp +++ b/nn/common/operations/Broadcast.cpp @@ -29,16 +29,14 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" #include "Tracing.h" +#include "nnapi/Types.h" namespace android { namespace nn { -using namespace hal; - namespace broadcast { constexpr uint32_t kNumInputs = 3; @@ -53,16 +51,16 @@ namespace { #define ANDROID_NN_MACRO_DISPATCH(macro) \ switch (activation) { \ - case (int32_t)FusedActivationFunc::NONE: \ + case static_cast<int32_t>(FusedActivationFunc::NONE): \ macro(kNone); \ break; \ - case (int32_t)FusedActivationFunc::RELU: \ + case static_cast<int32_t>(FusedActivationFunc::RELU): \ macro(kRelu); \ break; \ - case (int32_t)FusedActivationFunc::RELU1: \ + case static_cast<int32_t>(FusedActivationFunc::RELU1): \ macro(kRelu1); \ break; \ - case (int32_t)FusedActivationFunc::RELU6: \ + case static_cast<int32_t>(FusedActivationFunc::RELU6): \ macro(kRelu6); \ break; \ default: \ @@ -464,7 +462,7 @@ bool validate(OperationType opType, const IOperationValidationContext* context) inputType == OperandType::TENSOR_INT32) { NN_RET_CHECK(validateHalVersion(context, std::max(HalVersion::V1_3, opIntroducedAt))); } else { - NN_RET_CHECK_FAIL() << "Unsupported tensor type for operation " << getOperationName(opType); + NN_RET_CHECK_FAIL() << "Unsupported tensor type for operation " << opType; } const Shape& input1 = context->getInputShape(kInputTensor1); const Shape& input2 = context->getInputShape(kInputTensor2); diff --git a/nn/common/operations/Cast.cpp b/nn/common/operations/Cast.cpp index 77e35afb0..aef3baf79 100644 --- a/nn/common/operations/Cast.cpp +++ b/nn/common/operations/Cast.cpp @@ -20,7 +20,6 @@ #include <algorithm> -#include "HalInterfaces.h" #include "Operations.h" #include "Tracing.h" @@ -30,8 +29,6 @@ namespace cast { namespace { -using namespace hal; - template <typename FromT, typename ToT> void copyCast(const FromT* in, ToT* out, int numElements) { std::transform(in, in + numElements, out, [](FromT a) -> ToT { diff --git a/nn/common/operations/ChannelShuffle.cpp b/nn/common/operations/ChannelShuffle.cpp index 7abf224c8..779a8d811 100644 --- a/nn/common/operations/ChannelShuffle.cpp +++ b/nn/common/operations/ChannelShuffle.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -25,8 +24,6 @@ namespace android { namespace nn { namespace channel_shuffle { -using namespace hal; - constexpr char kOperationName[] = "CHANNEL_SHUFFLE"; constexpr uint32_t kNumInputs = 3; diff --git a/nn/common/operations/Comparisons.cpp b/nn/common/operations/Comparisons.cpp index a8f86228a..50ed806a0 100644 --- a/nn/common/operations/Comparisons.cpp +++ b/nn/common/operations/Comparisons.cpp @@ -19,7 +19,6 @@ #include <functional> #include <vector> -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" #include "OperationsUtils.h" @@ -37,8 +36,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename DataType, typename ComparisonType> bool compute(const std::function<bool(ComparisonType, ComparisonType)>& func, const DataType* aData, const Shape& aShape, const DataType* bData, const Shape& bShape, bool8* outputData, @@ -135,7 +132,7 @@ bool validate(const IOperationValidationContext* context) { inputType == OperandType::TENSOR_FLOAT32 || inputType == OperandType::TENSOR_INT32 || inputType == OperandType::TENSOR_QUANT8_ASYMM || inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Unsupported input operand type for comparison op: " << toString(inputType); + << "Unsupported input operand type for comparison op: " << inputType; NN_RET_CHECK(validateInputTypes(context, {inputType, inputType})); NN_RET_CHECK(validateOutputTypes(context, {OperandType::TENSOR_BOOL8})); if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { diff --git a/nn/common/operations/Concatenation.cpp b/nn/common/operations/Concatenation.cpp index 08c9c6130..6de5baded 100644 --- a/nn/common/operations/Concatenation.cpp +++ b/nn/common/operations/Concatenation.cpp @@ -27,7 +27,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" @@ -42,8 +41,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> bool concatenation(const std::vector<const T*>& inputDataPtrs, const std::vector<Shape>& inputShapes, int32_t axis, T* outputData, diff --git a/nn/common/operations/Conv2D.cpp b/nn/common/operations/Conv2D.cpp index f34e9080c..5b7d8d0de 100644 --- a/nn/common/operations/Conv2D.cpp +++ b/nn/common/operations/Conv2D.cpp @@ -26,7 +26,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Operations.h" #include "OperationsUtils.h" @@ -49,8 +48,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - // If possible we will use this static buffer for the tensor. constexpr size_t kStaticBufferSize = 1605632; char static_scratch_buffer[kStaticBufferSize]; @@ -566,7 +563,9 @@ bool validate(const IOperationValidationContext* context) { OperandType::INT32}; if (filterType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { - NN_RET_CHECK_EQ(context->getInputExtraParams(kFilterTensor).channelQuant().channelDim, + NN_RET_CHECK_EQ(std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .channelDim, 0) << "Unsupported filter tensor channel dimension for operation " << kOperationName; @@ -727,7 +726,9 @@ bool execute(IOperationExecutionContext* context) { context->getInputShape(kInputTensor), context->getInputBuffer<int8_t>(kFilterTensor), context->getInputShape(kFilterTensor), - context->getInputExtraParams(kFilterTensor).channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .scales.data(), context->getInputBuffer<int32_t>(kBiasTensor), context->getInputShape(kBiasTensor), param.padding_left, param.padding_right, param.padding_top, param.padding_bottom, @@ -758,7 +759,9 @@ bool execute(IOperationExecutionContext* context) { context->getInputShape(kInputTensor), context->getInputBuffer<int8_t>(kFilterTensor), context->getInputShape(kFilterTensor), - context->getInputExtraParams(kFilterTensor).channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .scales.data(), context->getInputBuffer<int32_t>(kBiasTensor), context->getInputShape(kBiasTensor), param.padding_left, param.padding_right, param.padding_top, param.padding_bottom, diff --git a/nn/common/operations/DepthwiseConv2D.cpp b/nn/common/operations/DepthwiseConv2D.cpp index 32e8b5594..47bf0104f 100644 --- a/nn/common/operations/DepthwiseConv2D.cpp +++ b/nn/common/operations/DepthwiseConv2D.cpp @@ -42,8 +42,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - struct DepthwiseConv2dParam { int32_t padding_left, padding_right; int32_t padding_top, padding_bottom; @@ -443,7 +441,9 @@ bool validate(const IOperationValidationContext* context) { filterType == inputType) << "Unsupported filter tensor type for operation " << kOperationName; if (filterType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { - NN_RET_CHECK_EQ(context->getInputExtraParams(kFilterTensor).channelQuant().channelDim, + NN_RET_CHECK_EQ(std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .channelDim, 3) << "Unsupported filter tensor channel dimension for operation " << kOperationName; @@ -607,7 +607,9 @@ bool execute(IOperationExecutionContext* context) { context->getInputShape(kInputTensor), context->getInputBuffer<int8_t>(kFilterTensor), context->getInputShape(kFilterTensor), - context->getInputExtraParams(kFilterTensor).channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .scales.data(), context->getInputBuffer<int32_t>(kBiasTensor), context->getInputShape(kBiasTensor), param.padding_left, param.padding_right, param.padding_top, param.padding_bottom, @@ -639,7 +641,9 @@ bool execute(IOperationExecutionContext* context) { context->getInputShape(kInputTensor), context->getInputBuffer<int8_t>(kFilterTensor), context->getInputShape(kFilterTensor), - context->getInputExtraParams(kFilterTensor).channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .scales.data(), context->getInputBuffer<int32_t>(kBiasTensor), context->getInputShape(kBiasTensor), param.padding_left, param.padding_right, param.padding_top, param.padding_bottom, diff --git a/nn/common/operations/Dequantize.cpp b/nn/common/operations/Dequantize.cpp index 2fb2d5cb0..7b8114347 100644 --- a/nn/common/operations/Dequantize.cpp +++ b/nn/common/operations/Dequantize.cpp @@ -17,7 +17,6 @@ #include "OperationsUtils.h" #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" @@ -33,8 +32,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename InputType, typename OutputType> bool compute(const InputType* inputData, const Shape& inputShape, OutputType* outputData) { const int numElements = getNumberOfElements(inputShape); @@ -52,7 +49,8 @@ bool computePerChannel(const int8_t* inputData, const Shape& inputShape, OutputT // First we calculate a stride which is the number of elements we need to // skip to change an index along a dimension with different quantization // scales. - const int channelDim = inputShape.extraParams.channelQuant().channelDim; + const int channelDim = + std::get<Operand::SymmPerChannelQuantParams>(inputShape.extraParams).channelDim; int stride = 1; for (int i = getNumberOfDimensions(inputShape) - 1; i > channelDim; --i) { stride *= getSizeOfDimension(inputShape, i); @@ -67,7 +65,8 @@ bool computePerChannel(const int8_t* inputData, const Shape& inputShape, OutputT // size of the dimension (so that we don't have an overflow if the // channelDim is not 0). const int scaleIndex = (i / stride) % getSizeOfDimension(inputShape, channelDim); - const float scale = inputShape.extraParams.channelQuant().scales[scaleIndex]; + const float scale = std::get<Operand::SymmPerChannelQuantParams>(inputShape.extraParams) + .scales[scaleIndex]; const int32_t value = inputData[i]; outputData[i] = static_cast<OutputType>(scale * (value - zeroPoint)); } @@ -97,10 +96,10 @@ bool validate(const IOperationValidationContext* context) { inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED || inputType == OperandType::TENSOR_QUANT8_SYMM || inputType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) - << "Unsupported input operand type for DEQUANTIZE op: " << toString(inputType); + << "Unsupported input operand type for DEQUANTIZE op: " << inputType; NN_RET_CHECK(outputType == OperandType::TENSOR_FLOAT16 || outputType == OperandType::TENSOR_FLOAT32) - << "Unsupported output operand type for DEQUANTIZE op: " << toString(outputType); + << "Unsupported output operand type for DEQUANTIZE op: " << outputType; return validateHalVersion(context, HalVersion::V1_2); } @@ -155,7 +154,7 @@ bool execute(IOperationExecutionContext* context) { } } NN_RET_CHECK_FAIL() << "Unsupported tensor types combination for dequantize op. (input type: " - << toString(inputType) << " output type: " << toString(outputType) << ")"; + << inputType << " output type: " << outputType << ")"; } } // namespace dequantize diff --git a/nn/common/operations/Elementwise.cpp b/nn/common/operations/Elementwise.cpp index 82a268763..3ddae9096 100644 --- a/nn/common/operations/Elementwise.cpp +++ b/nn/common/operations/Elementwise.cpp @@ -18,7 +18,6 @@ #include <cmath> -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -35,8 +34,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename IntermediateType, typename T> inline bool compute(IntermediateType func(IntermediateType), const T* input, const Shape& shape, T* output) { diff --git a/nn/common/operations/Elu.cpp b/nn/common/operations/Elu.cpp index 07304e7d7..dfb221c63 100644 --- a/nn/common/operations/Elu.cpp +++ b/nn/common/operations/Elu.cpp @@ -20,7 +20,6 @@ #include <cmath> #include <vector> -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" #include "OperationsUtils.h" @@ -30,8 +29,6 @@ namespace android { namespace nn { namespace elu { -using namespace hal; - constexpr uint32_t kNumInputs = 2; constexpr uint32_t kInputTensor = 0; constexpr uint32_t kAlphaScalar = 1; diff --git a/nn/common/operations/EmbeddingLookup.cpp b/nn/common/operations/EmbeddingLookup.cpp index 12e4a65a9..5ff26e8e0 100644 --- a/nn/common/operations/EmbeddingLookup.cpp +++ b/nn/common/operations/EmbeddingLookup.cpp @@ -19,7 +19,6 @@ #include "EmbeddingLookup.h" #include "CpuExecutor.h" -#include "HalInterfaces.h" #include "Operations.h" #include "Tracing.h" @@ -27,8 +26,6 @@ namespace android { namespace nn { -using namespace hal; - EmbeddingLookup::EmbeddingLookup(const Operation& operation, RunTimeOperandInfo* operands) { value_ = GetInput(operation, operands, kValueTensor); lookup_ = GetInput(operation, operands, kLookupTensor); diff --git a/nn/common/operations/EmbeddingLookup.h b/nn/common/operations/EmbeddingLookup.h index 9a82ddabf..0388b355a 100644 --- a/nn/common/operations/EmbeddingLookup.h +++ b/nn/common/operations/EmbeddingLookup.h @@ -19,7 +19,7 @@ #include <vector> -#include "HalInterfaces.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -28,7 +28,7 @@ struct RunTimeOperandInfo; class EmbeddingLookup { public: - EmbeddingLookup(const hal::Operation& operation, RunTimeOperandInfo* operands); + EmbeddingLookup(const Operation& operation, RunTimeOperandInfo* operands); bool Eval(); diff --git a/nn/common/operations/Fill.cpp b/nn/common/operations/Fill.cpp index a6b390698..a23362759 100644 --- a/nn/common/operations/Fill.cpp +++ b/nn/common/operations/Fill.cpp @@ -17,7 +17,6 @@ #include "OperationsUtils.h" #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "OperationResolver.h" namespace android { @@ -33,8 +32,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> bool executeTyped(IOperationExecutionContext* context) { T* output = context->getOutputBuffer<T>(kOutputTensor); @@ -58,7 +55,7 @@ bool getValueType(OperandType outputType, OperandType* valueType) { *valueType = OperandType::INT32; return true; default: - NN_RET_CHECK_FAIL() << "Unsupported value type for fill op: " << toString(outputType); + NN_RET_CHECK_FAIL() << "Unsupported value type for fill op: " << outputType; } } @@ -73,7 +70,7 @@ bool validate(const IOperationValidationContext* context) { NN_RET_CHECK(outputType == OperandType::TENSOR_FLOAT16 || outputType == OperandType::TENSOR_FLOAT32 || outputType == OperandType::TENSOR_INT32) - << "Unsupported output type for fill op: " << toString(outputType); + << "Unsupported output type for fill op: " << outputType; NN_RET_CHECK(validateOutputTypes(context, {outputType})); OperandType valueType; diff --git a/nn/common/operations/FullyConnected.cpp b/nn/common/operations/FullyConnected.cpp index 9bdd0bab2..9fcc072ff 100644 --- a/nn/common/operations/FullyConnected.cpp +++ b/nn/common/operations/FullyConnected.cpp @@ -24,7 +24,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" @@ -45,8 +44,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - // executionMutex is used to protect concurrent access of non-threadsafe resources // like gemmlowp::GemmContext. // std::mutex is safe for pthreads on Android. diff --git a/nn/common/operations/Gather.cpp b/nn/common/operations/Gather.cpp index d496d6ada..e73a22eb5 100644 --- a/nn/common/operations/Gather.cpp +++ b/nn/common/operations/Gather.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -37,8 +36,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> inline bool eval(const T* inputData, const Shape& inputShape, int32_t axis, const int32_t* indicesData, const Shape& indicesShape, T* outputData) { diff --git a/nn/common/operations/GenerateProposals.cpp b/nn/common/operations/GenerateProposals.cpp index 4e3aa3fb0..2ef733e14 100644 --- a/nn/common/operations/GenerateProposals.cpp +++ b/nn/common/operations/GenerateProposals.cpp @@ -24,7 +24,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -35,8 +34,6 @@ namespace bbox_ops { namespace { -using namespace hal; - struct BoxEncodingCorner { float x1, y1, x2, y2; }; diff --git a/nn/common/operations/HashtableLookup.cpp b/nn/common/operations/HashtableLookup.cpp index 287c866d0..cfb9d9812 100644 --- a/nn/common/operations/HashtableLookup.cpp +++ b/nn/common/operations/HashtableLookup.cpp @@ -19,7 +19,6 @@ #include "HashtableLookup.h" #include "CpuExecutor.h" -#include "HalInterfaces.h" #include "Operations.h" #include "Tracing.h" @@ -29,8 +28,6 @@ namespace nn { namespace { -using namespace hal; - int greater(const void* a, const void* b) { return *static_cast<const int*>(a) - *static_cast<const int*>(b); } diff --git a/nn/common/operations/HashtableLookup.h b/nn/common/operations/HashtableLookup.h index c0921e0fd..1ae554f56 100644 --- a/nn/common/operations/HashtableLookup.h +++ b/nn/common/operations/HashtableLookup.h @@ -19,7 +19,7 @@ #include <vector> -#include "HalInterfaces.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -28,7 +28,7 @@ struct RunTimeOperandInfo; class HashtableLookup { public: - HashtableLookup(const hal::Operation& operation, RunTimeOperandInfo* operands); + HashtableLookup(const Operation& operation, RunTimeOperandInfo* operands); bool Eval(); diff --git a/nn/common/operations/HeatmapMaxKeypoint.cpp b/nn/common/operations/HeatmapMaxKeypoint.cpp index 3608ca59d..a07e1428c 100644 --- a/nn/common/operations/HeatmapMaxKeypoint.cpp +++ b/nn/common/operations/HeatmapMaxKeypoint.cpp @@ -22,7 +22,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -44,8 +43,6 @@ constexpr uint32_t kOutputKeypointTensor = 1; namespace { -using namespace hal; - // This function uses Taylor expansion up to the quatratic term to approximate bicubic // upscaling result. // 2nd order Taylor expansion: D(x) = D - b'x + 1/2 * x'Ax diff --git a/nn/common/operations/InstanceNormalization.cpp b/nn/common/operations/InstanceNormalization.cpp index 75b907b64..0ce21d03e 100644 --- a/nn/common/operations/InstanceNormalization.cpp +++ b/nn/common/operations/InstanceNormalization.cpp @@ -20,7 +20,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" @@ -42,8 +41,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> inline bool instanceNormNhwc(const T* inputData, const Shape& inputShape, T gamma, T beta, T epsilon, T* outputData, const Shape& outputShape) { diff --git a/nn/common/operations/L2Normalization.cpp b/nn/common/operations/L2Normalization.cpp index 1f0c9d051..f86ab8011 100644 --- a/nn/common/operations/L2Normalization.cpp +++ b/nn/common/operations/L2Normalization.cpp @@ -23,7 +23,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" @@ -42,8 +41,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - inline bool l2normFloat32Impl(const float* inputData, const Shape& inputShape, int32_t axis, float* outputData, const Shape& outputShape) { NNTRACE_TRANS("l2normFloat32"); diff --git a/nn/common/operations/LSHProjection.cpp b/nn/common/operations/LSHProjection.cpp index bdb106e18..14d7a790d 100644 --- a/nn/common/operations/LSHProjection.cpp +++ b/nn/common/operations/LSHProjection.cpp @@ -18,19 +18,18 @@ #include "LSHProjection.h" +#include <utils/hash/farmhash.h> + +#include <memory> + #include "CpuExecutor.h" -#include "HalInterfaces.h" #include "Tracing.h" #include "Utils.h" - -#include <utils/hash/farmhash.h> -#include <memory> +#include "nnapi/Types.h" namespace android { namespace nn { -using namespace hal; - LSHProjection::LSHProjection(const Operation& operation, RunTimeOperandInfo* operands) { input_ = GetInput(operation, operands, kInputTensor); weight_ = GetInput(operation, operands, kWeightTensor); @@ -112,7 +111,7 @@ int runningSignBit(const RunTimeOperandInfo* input, const RunTimeOperandInfo* we int64_t hash_signature = farmhash::Fingerprint64(key.get(), key_bytes); double running_value = static_cast<double>(hash_signature); input_ptr += input_item_bytes; - if (weight->lifetime == OperandLifeTime::NO_VALUE) { + if (weight->lifetime == Operand::LifeTime::NO_VALUE) { score += running_value; } else { score += static_cast<double>(reinterpret_cast<T*>(weight->buffer)[i]) * running_value; diff --git a/nn/common/operations/LSHProjection.h b/nn/common/operations/LSHProjection.h index 520f58a89..3a953a0ad 100644 --- a/nn/common/operations/LSHProjection.h +++ b/nn/common/operations/LSHProjection.h @@ -19,7 +19,7 @@ #include <vector> -#include "HalInterfaces.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -36,9 +36,9 @@ struct Shape; class LSHProjection { public: - LSHProjection(const hal::Operation& operation, RunTimeOperandInfo* operands); + LSHProjection(const Operation& operation, RunTimeOperandInfo* operands); - static bool Prepare(const hal::Operation& operation, RunTimeOperandInfo* operands, + static bool Prepare(const Operation& operation, RunTimeOperandInfo* operands, Shape* outputShape); template <typename T> bool Eval(); diff --git a/nn/common/operations/LSTM.cpp b/nn/common/operations/LSTM.cpp index 3051cfd99..e64d0c495 100644 --- a/nn/common/operations/LSTM.cpp +++ b/nn/common/operations/LSTM.cpp @@ -22,18 +22,16 @@ #include "CpuExecutor.h" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationsUtils.h" #include "Tracing.h" #include "Utils.h" +#include "nnapi/Types.h" namespace android { namespace nn { namespace { -using namespace hal; - template <typename T> inline T* GetBuffer(RunTimeOperandInfo* operand) { return reinterpret_cast<T*>(operand->buffer); @@ -113,7 +111,7 @@ LSTMCell::LSTMCell(const Operation& operation, RunTimeOperandInfo* operands) { } else { // For LSTM from HAL v1.0 assign operands with no values static RunTimeOperandInfo no_value; - no_value.lifetime = OperandLifeTime::NO_VALUE; + no_value.lifetime = Operand::LifeTime::NO_VALUE; input_layer_norm_weights_ = &no_value; forget_layer_norm_weights_ = &no_value; @@ -221,8 +219,8 @@ bool LSTMCell::CheckInputTensorDimensions( // omitted ones can be omited in case CIFG LSTM is used. params->use_layer_norm = !IsNullInput(output_layer_norm_weights); - params->use_projection_weight = (projection_weights->lifetime != OperandLifeTime::NO_VALUE); - params->use_projection_bias = (projection_bias->lifetime != OperandLifeTime::NO_VALUE); + params->use_projection_weight = (projection_weights->lifetime != Operand::LifeTime::NO_VALUE); + params->use_projection_bias = (projection_bias->lifetime != Operand::LifeTime::NO_VALUE); // Make sure the input gate bias is present only when not a CIFG-LSTM. if (params->use_cifg) { diff --git a/nn/common/operations/LSTM.h b/nn/common/operations/LSTM.h index b48c3df3c..dc6a43cfa 100644 --- a/nn/common/operations/LSTM.h +++ b/nn/common/operations/LSTM.h @@ -24,7 +24,7 @@ #include <vector> #include "ActivationFunctor.h" -#include "HalInterfaces.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -48,9 +48,9 @@ struct Shape; class LSTMCell { public: - LSTMCell(const hal::Operation& operation, RunTimeOperandInfo* operands); + LSTMCell(const Operation& operation, RunTimeOperandInfo* operands); - bool Prepare(const hal::Operation& operation, RunTimeOperandInfo* operands, Shape* scratchShape, + bool Prepare(const Operation& operation, RunTimeOperandInfo* operands, Shape* scratchShape, Shape* outputStateShape, Shape* cellStateShape, Shape* outputShape); bool Eval(); diff --git a/nn/common/operations/LocalResponseNormalization.cpp b/nn/common/operations/LocalResponseNormalization.cpp index 40220e1b0..26a7a002a 100644 --- a/nn/common/operations/LocalResponseNormalization.cpp +++ b/nn/common/operations/LocalResponseNormalization.cpp @@ -22,7 +22,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" @@ -45,8 +44,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - inline bool localResponseNormFloat32Impl(const float* inputData, const Shape& inputShape, int32_t radius, float bias, float alpha, float beta, int32_t axis, float* outputData, diff --git a/nn/common/operations/LogSoftmax.cpp b/nn/common/operations/LogSoftmax.cpp index 4132ef9ae..fdcccf851 100644 --- a/nn/common/operations/LogSoftmax.cpp +++ b/nn/common/operations/LogSoftmax.cpp @@ -16,19 +16,18 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" +#include <algorithm> +#include <cmath> +#include <vector> + #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" -#include <cmath> - namespace android { namespace nn { namespace log_softmax { -using namespace hal; - constexpr char kOperationName[] = "LOG_SOFTMAX"; constexpr uint32_t kNumInputs = 3; diff --git a/nn/common/operations/LogicalAndOr.cpp b/nn/common/operations/LogicalAndOr.cpp index 6ada724e0..9d7e5ce19 100644 --- a/nn/common/operations/LogicalAndOr.cpp +++ b/nn/common/operations/LogicalAndOr.cpp @@ -16,7 +16,9 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" +#include <functional> +#include <vector> + #include "IndexedShapeWrapper.h" #include "OperationResolver.h" #include "OperationsUtils.h" @@ -34,8 +36,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - bool compute(const std::function<bool(bool, bool)>& func, const bool8* aData, const Shape& aShape, const bool8* bData, const Shape& bShape, bool8* outputData, const Shape& outputShape) { IndexedShapeWrapper aShapeIndexed(aShape); diff --git a/nn/common/operations/LogicalNot.cpp b/nn/common/operations/LogicalNot.cpp index 8b418135e..c71538854 100644 --- a/nn/common/operations/LogicalNot.cpp +++ b/nn/common/operations/LogicalNot.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" @@ -32,8 +31,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - bool compute(const bool8* input, const Shape& shape, bool8* output) { const auto size = getNumberOfElements(shape); for (uint32_t i = 0; i < size; ++i) { diff --git a/nn/common/operations/MaximumMinimum.cpp b/nn/common/operations/MaximumMinimum.cpp index 91a4bb021..339172fd2 100644 --- a/nn/common/operations/MaximumMinimum.cpp +++ b/nn/common/operations/MaximumMinimum.cpp @@ -20,7 +20,6 @@ #include <vector> #include "MaximumMinimum.h" -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -31,8 +30,6 @@ namespace maximum_minimum { namespace { -using namespace hal; - template <typename T> bool evalGeneric(const T* aData, const Shape& aShape, const T* bData, const Shape& bShape, bool isMinimum, T* outputData, const Shape& outputShape) { @@ -124,7 +121,7 @@ bool eval(const void* in1, const Shape& shape1, const void* in2, const Shape& sh reinterpret_cast<int8_t*>(output), outputShape); } default: { - LOG(ERROR) << "Unsupported data type: " << toString(shape1.type); + LOG(ERROR) << "Unsupported data type: " << shape1.type; return false; } } diff --git a/nn/common/operations/Multinomial.cpp b/nn/common/operations/Multinomial.cpp index 7e1d2c6f8..80fb7e880 100644 --- a/nn/common/operations/Multinomial.cpp +++ b/nn/common/operations/Multinomial.cpp @@ -20,7 +20,6 @@ #include "CpuExecutor.h" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "Tracing.h" #include "guarded_philox_random.h" @@ -37,8 +36,6 @@ namespace nn { namespace { -using namespace hal; - template <typename T> inline T* GetBuffer(RunTimeOperandInfo* operand) { return reinterpret_cast<T*>(operand->buffer); diff --git a/nn/common/operations/Multinomial.h b/nn/common/operations/Multinomial.h index 0f5434e9b..bdfe58757 100644 --- a/nn/common/operations/Multinomial.h +++ b/nn/common/operations/Multinomial.h @@ -23,7 +23,7 @@ #include <cmath> #include <vector> -#include "HalInterfaces.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -33,9 +33,9 @@ struct Shape; class Multinomial { public: - Multinomial(const hal::Operation& operation, RunTimeOperandInfo* operands); + Multinomial(const Operation& operation, RunTimeOperandInfo* operands); - static bool Prepare(const hal::Operation& operation, RunTimeOperandInfo* operands, + static bool Prepare(const Operation& operation, RunTimeOperandInfo* operands, Shape* outputShape); bool Eval(); diff --git a/nn/common/operations/MultinomialTest.cpp b/nn/common/operations/MultinomialTest.cpp index e34de63dc..668ed36b3 100644 --- a/nn/common/operations/MultinomialTest.cpp +++ b/nn/common/operations/MultinomialTest.cpp @@ -14,17 +14,17 @@ * limitations under the License. */ -#include "Multinomial.h" +#include <gmock/gmock-matchers.h> +#include <gtest/gtest.h> + +#include <unsupported/Eigen/CXX11/Tensor> +#include <vector> -#include "HalInterfaces.h" +#include "Multinomial.h" #include "NeuralNetworksWrapper.h" #include "philox_random.h" #include "simple_philox.h" -#include <gmock/gmock-matchers.h> -#include <gtest/gtest.h> -#include <unsupported/Eigen/CXX11/Tensor> - namespace android { namespace nn { namespace wrapper { diff --git a/nn/common/operations/Neg.cpp b/nn/common/operations/Neg.cpp index 48d962c9a..bf2172704 100644 --- a/nn/common/operations/Neg.cpp +++ b/nn/common/operations/Neg.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -37,8 +36,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> inline bool compute(const T* input, const Shape& shape, T* output) { const auto size = getNumberOfElements(shape); diff --git a/nn/common/operations/PRelu.cpp b/nn/common/operations/PRelu.cpp index a799a84cb..7e0c8c371 100644 --- a/nn/common/operations/PRelu.cpp +++ b/nn/common/operations/PRelu.cpp @@ -19,7 +19,6 @@ #include <algorithm> #include <vector> -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" #include "OperationsUtils.h" @@ -31,8 +30,6 @@ namespace android { namespace nn { namespace prelu { -using namespace hal; - constexpr char kOperationName[] = "PRELU"; constexpr uint32_t kNumInputs = 2; diff --git a/nn/common/operations/Pooling.cpp b/nn/common/operations/Pooling.cpp index 3ffa70fb9..62594c783 100644 --- a/nn/common/operations/Pooling.cpp +++ b/nn/common/operations/Pooling.cpp @@ -22,15 +22,12 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" namespace android { namespace nn { -using namespace hal; - namespace pooling { constexpr uint32_t kInputTensor = 0; @@ -334,8 +331,7 @@ bool validate(OperationType opType, const IOperationValidationContext* context) OperandType::INT32, }; } else { - NN_RET_CHECK_FAIL() << "Unsupported input tensor type for operation " - << getOperationName(opType); + NN_RET_CHECK_FAIL() << "Unsupported input tensor type for operation " << opType; } if (inputCount >= 10) { diff --git a/nn/common/operations/Pow.cpp b/nn/common/operations/Pow.cpp index 40c4adf02..03892a230 100644 --- a/nn/common/operations/Pow.cpp +++ b/nn/common/operations/Pow.cpp @@ -17,11 +17,11 @@ #define LOG_TAG "Operations" #include "Pow.h" -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationsUtils.h" #include <cmath> +#include <vector> namespace android { namespace nn { @@ -29,8 +29,6 @@ namespace pow { namespace { -using namespace hal; - template <typename T> bool evalGeneric(const T* baseData, const Shape& baseShape, const T* exponentData, const Shape& exponentShape, T* outputData, const Shape& outputShape) { @@ -81,7 +79,7 @@ bool eval(const void* baseData, const Shape& baseShape, const void* exponentData reinterpret_cast<float*>(outputData), outputShape); } break; default: { - LOG(ERROR) << "Unsupported data type: " << toString(baseShape.type); + LOG(ERROR) << "Unsupported data type: " << baseShape.type; return false; } } diff --git a/nn/common/operations/QLSTM.cpp b/nn/common/operations/QLSTM.cpp index 3b2dd0508..68a9489fc 100644 --- a/nn/common/operations/QLSTM.cpp +++ b/nn/common/operations/QLSTM.cpp @@ -101,8 +101,6 @@ inline bool hasTensor(IOperationExecutionContext* context, const uint32_t tensor } // namespace -using hal::OperandType; - bool validate(const IOperationValidationContext* context) { NN_RET_CHECK_EQ(context->getNumInputs(), kNumInputs); NN_RET_CHECK_EQ(context->getNumOutputs(), kNumOutputs); diff --git a/nn/common/operations/Quantize.cpp b/nn/common/operations/Quantize.cpp index fa04bdd01..943a33dcb 100644 --- a/nn/common/operations/Quantize.cpp +++ b/nn/common/operations/Quantize.cpp @@ -17,7 +17,6 @@ #include "OperationsUtils.h" #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" #include "Tracing.h" @@ -37,8 +36,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> bool quantizeToQuant8(const T* inputData, uint8_t* outputData, const Shape& outputShape) { NNTRACE_COMP("quantizeToQuant8"); @@ -75,10 +72,10 @@ bool validate(const IOperationValidationContext* context) { NN_RET_CHECK(inputType == OperandType::TENSOR_FLOAT16 || inputType == OperandType::TENSOR_FLOAT32) - << "Unsupported input operand type for QUANTIZE op: " << toString(inputType); + << "Unsupported input operand type for QUANTIZE op: " << inputType; NN_RET_CHECK(outputType == OperandType::TENSOR_QUANT8_ASYMM || outputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Unsupported output operand type for QUANTIZE op: " << toString(outputType); + << "Unsupported output operand type for QUANTIZE op: " << outputType; if (outputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { return validateHalVersion(context, HalVersion::V1_3); } else { @@ -121,8 +118,7 @@ bool execute(IOperationExecutionContext* context) { } } NN_RET_CHECK_FAIL() << "Unsupported tensor types combination for QUANTIZE op. (input type: " - << toString(inputType) - << " output type: " << toString(context->getOutputType(kOutputTensor)) + << inputType << " output type: " << context->getOutputType(kOutputTensor) << ")"; } diff --git a/nn/common/operations/QuantizedLSTM.cpp b/nn/common/operations/QuantizedLSTM.cpp index e059026ff..f07bc0a40 100644 --- a/nn/common/operations/QuantizedLSTM.cpp +++ b/nn/common/operations/QuantizedLSTM.cpp @@ -20,7 +20,6 @@ #include "CpuExecutor.h" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "Tracing.h" @@ -34,8 +33,6 @@ namespace nn { namespace { -using namespace hal; - template <typename T> inline T* GetBuffer(RunTimeOperandInfo* operand) { return reinterpret_cast<T*>(operand->buffer); diff --git a/nn/common/operations/QuantizedLSTM.h b/nn/common/operations/QuantizedLSTM.h index 76e74c638..61963c03f 100644 --- a/nn/common/operations/QuantizedLSTM.h +++ b/nn/common/operations/QuantizedLSTM.h @@ -28,9 +28,9 @@ struct RunTimeOperandInfo; class QuantizedLSTMCell { public: - QuantizedLSTMCell(const hal::Operation& operation, RunTimeOperandInfo* operands); + QuantizedLSTMCell(const Operation& operation, RunTimeOperandInfo* operands); - static bool prepare(const hal::Operation& operation, RunTimeOperandInfo* operands, + static bool prepare(const Operation& operation, RunTimeOperandInfo* operands, Shape* cellStateShape, Shape* outputShape); bool eval(); diff --git a/nn/common/operations/RNN.cpp b/nn/common/operations/RNN.cpp index 259c0915e..f584f0e1b 100644 --- a/nn/common/operations/RNN.cpp +++ b/nn/common/operations/RNN.cpp @@ -22,15 +22,12 @@ #include "CpuExecutor.h" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "Tracing.h" namespace android { namespace nn { -using namespace hal; - RNN::RNN(const Operation& operation, RunTimeOperandInfo* operands) { NNTRACE_TRANS("RNN::RNN"); input_ = GetInput(operation, operands, kInputTensor); diff --git a/nn/common/operations/RNN.h b/nn/common/operations/RNN.h index 245eb1df3..0a5765b2e 100644 --- a/nn/common/operations/RNN.h +++ b/nn/common/operations/RNN.h @@ -20,7 +20,7 @@ #include <vector> #include "ActivationFunctor.h" -#include "HalInterfaces.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -30,9 +30,9 @@ struct Shape; class RNN { public: - RNN(const hal::Operation& operation, RunTimeOperandInfo* operands); + RNN(const Operation& operation, RunTimeOperandInfo* operands); - static bool Prepare(const hal::Operation& operation, RunTimeOperandInfo* operands, + static bool Prepare(const Operation& operation, RunTimeOperandInfo* operands, Shape* hiddenStateShape, Shape* outputShape); bool Eval(); diff --git a/nn/common/operations/Rank.cpp b/nn/common/operations/Rank.cpp index 5f744375d..8a6931beb 100644 --- a/nn/common/operations/Rank.cpp +++ b/nn/common/operations/Rank.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Utils.h" @@ -34,19 +33,19 @@ constexpr uint32_t kOutputScalar = 0; bool validate(const IOperationValidationContext* context) { NN_RET_CHECK_EQ(context->getNumInputs(), kNumInputs); NN_RET_CHECK_EQ(context->getNumOutputs(), kNumOutputs); - hal::OperandType inputType = context->getInputType(kInputTensor); - NN_RET_CHECK(inputType == hal::OperandType::TENSOR_FLOAT16 || - inputType == hal::OperandType::TENSOR_FLOAT32 || - inputType == hal::OperandType::TENSOR_INT32 || - inputType == hal::OperandType::TENSOR_QUANT8_ASYMM || - inputType == hal::OperandType::TENSOR_QUANT16_SYMM || - inputType == hal::OperandType::TENSOR_BOOL8 || - inputType == hal::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL || - inputType == hal::OperandType::TENSOR_QUANT16_ASYMM || - inputType == hal::OperandType::TENSOR_QUANT8_SYMM || - inputType == hal::OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Incorrect input type for a RANK op: " << toString(inputType); - NN_RET_CHECK(validateOutputTypes(context, {hal::OperandType::INT32})); + OperandType inputType = context->getInputType(kInputTensor); + NN_RET_CHECK(inputType == OperandType::TENSOR_FLOAT16 || + inputType == OperandType::TENSOR_FLOAT32 || + inputType == OperandType::TENSOR_INT32 || + inputType == OperandType::TENSOR_QUANT8_ASYMM || + inputType == OperandType::TENSOR_QUANT16_SYMM || + inputType == OperandType::TENSOR_BOOL8 || + inputType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL || + inputType == OperandType::TENSOR_QUANT16_ASYMM || + inputType == OperandType::TENSOR_QUANT8_SYMM || + inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) + << "Incorrect input type for a RANK op: " << inputType; + NN_RET_CHECK(validateOutputTypes(context, {OperandType::INT32})); return validateHalVersion(context, HalVersion::V1_3); } diff --git a/nn/common/operations/Reduce.cpp b/nn/common/operations/Reduce.cpp index 220a4dcad..c56771cc3 100644 --- a/nn/common/operations/Reduce.cpp +++ b/nn/common/operations/Reduce.cpp @@ -22,7 +22,6 @@ #include <limits> #include <vector> -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -46,8 +45,6 @@ constexpr _Float16 kFloat16Lowest = -kFloat16Max; namespace { -using namespace hal; - template <typename T> inline bool compute(IOperationExecutionContext* context, T init, T func(T, T)) { const Shape inputShape = context->getInputShape(kInputTensor); diff --git a/nn/common/operations/ResizeImageOps.cpp b/nn/common/operations/ResizeImageOps.cpp index c33abaf54..90420994c 100644 --- a/nn/common/operations/ResizeImageOps.cpp +++ b/nn/common/operations/ResizeImageOps.cpp @@ -23,15 +23,12 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" namespace android { namespace nn { -using namespace hal; - namespace resize_image { constexpr uint32_t kNumInputs = 4; @@ -178,7 +175,7 @@ bool validate(OperationType opType, const IOperationValidationContext* context) } else if (opType == OperationType::RESIZE_NEAREST_NEIGHBOR) { NN_RET_CHECK(numInputs >= kNumInputs && numInputs <= kNumInputs + kNumOptionalInputs); } else { - NN_RET_CHECK_FAIL() << "Unsupported operation " << getOperationName(opType); + NN_RET_CHECK_FAIL() << "Unsupported operation " << opType; } NN_RET_CHECK_EQ(context->getNumOutputs(), kNumOutputs); auto inputType = context->getInputType(kInputTensor); @@ -188,7 +185,7 @@ bool validate(OperationType opType, const IOperationValidationContext* context) inputType == OperandType::TENSOR_FLOAT32 || inputType == OperandType::TENSOR_QUANT8_ASYMM || inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Unsupported tensor type for operation " << getOperationName(opType); + << "Unsupported tensor type for operation " << opType; if (inputType == OperandType::TENSOR_FLOAT16 || inputType == OperandType::TENSOR_QUANT8_ASYMM) { NN_RET_CHECK(validateHalVersion(context, HalVersion::V1_2)); } @@ -258,7 +255,7 @@ bool prepare(OperationType opType, IOperationExecutionContext* context) { static_cast<float>(inWidth) * static_cast<float>(context->getInputValue<_Float16>(kOutputWidthParamScalar))); } else { - NN_RET_CHECK_FAIL() << "Unsupported scalar type for operation " << getOperationName(opType); + NN_RET_CHECK_FAIL() << "Unsupported scalar type for operation " << opType; } NN_RET_CHECK_GT(height, 0); NN_RET_CHECK_GT(width, 0); @@ -304,8 +301,7 @@ bool execute(OperationType opType, IOperationExecutionContext* context) { context->getOutputShape(kOutputTensor)); default: - NN_RET_CHECK_FAIL() << "Unsupported tensor type for operation " - << getOperationName(opType); + NN_RET_CHECK_FAIL() << "Unsupported tensor type for operation " << opType; } } diff --git a/nn/common/operations/RoiAlign.cpp b/nn/common/operations/RoiAlign.cpp index b9daf45a3..01008cc9d 100644 --- a/nn/common/operations/RoiAlign.cpp +++ b/nn/common/operations/RoiAlign.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "Operations" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -51,8 +50,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T_Input, typename T_Roi> inline bool roiAlignNhwc(const T_Input* inputData, const Shape& inputShape, const T_Roi* roiData, const Shape& roiShape, const int32_t* batchSplitData, diff --git a/nn/common/operations/RoiPooling.cpp b/nn/common/operations/RoiPooling.cpp index a4f8214b7..373669aab 100644 --- a/nn/common/operations/RoiPooling.cpp +++ b/nn/common/operations/RoiPooling.cpp @@ -22,7 +22,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" #include "Tracing.h" @@ -48,8 +47,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T_Input, typename T_Roi> inline bool roiPoolingNhwc(const T_Input* inputData, const Shape& inputShape, const T_Roi* roiData, const Shape& roiShape, const int32_t* batchSplitData, diff --git a/nn/common/operations/SVDF.cpp b/nn/common/operations/SVDF.cpp index 83148389a..953e2a84f 100644 --- a/nn/common/operations/SVDF.cpp +++ b/nn/common/operations/SVDF.cpp @@ -20,7 +20,6 @@ #include "CpuExecutor.h" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include <algorithm> #include <vector> @@ -29,8 +28,6 @@ namespace android { namespace nn { -using namespace hal; - SVDF::SVDF(const Operation& operation, RunTimeOperandInfo* operands) { NNTRACE_TRANS("SVDF::SVDF"); input_ = GetInput(operation, operands, kInputTensor); diff --git a/nn/common/operations/SVDF.h b/nn/common/operations/SVDF.h index ca9b54e13..da185687c 100644 --- a/nn/common/operations/SVDF.h +++ b/nn/common/operations/SVDF.h @@ -23,7 +23,7 @@ #include <cmath> #include <vector> -#include "HalInterfaces.h" +#include "nnapi/Types.h" namespace android { namespace nn { @@ -38,10 +38,10 @@ struct Shape; class SVDF { public: - SVDF(const hal::Operation& operation, RunTimeOperandInfo* operands); + SVDF(const Operation& operation, RunTimeOperandInfo* operands); - static bool Prepare(const hal::Operation& operation, RunTimeOperandInfo* operands, - Shape* stateShape, Shape* outputShape); + static bool Prepare(const Operation& operation, RunTimeOperandInfo* operands, Shape* stateShape, + Shape* outputShape); bool Eval(); static constexpr int kInputTensor = 0; diff --git a/nn/common/operations/Select.cpp b/nn/common/operations/Select.cpp index 202659560..91053896d 100644 --- a/nn/common/operations/Select.cpp +++ b/nn/common/operations/Select.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "Operations" -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" #include "OperationsUtils.h" @@ -35,8 +34,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> bool compute(const bool8* conditionData, const Shape& conditionShape, const T* aData, const Shape& aShape, const T* bData, const Shape& bShape, T* outputData, @@ -78,7 +75,7 @@ bool validate(const IOperationValidationContext* context) { inputType == OperandType::TENSOR_INT32 || inputType == OperandType::TENSOR_QUANT8_ASYMM || inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Unsupported input operand type for select op: " << toString(inputType); + << "Unsupported input operand type for select op: " << inputType; NN_RET_CHECK(validateInputTypes(context, {OperandType::TENSOR_BOOL8, inputType, inputType})); NN_RET_CHECK(validateOutputTypes(context, {inputType})); return validateHalVersion(context, HalVersion::V1_2); diff --git a/nn/common/operations/Slice.cpp b/nn/common/operations/Slice.cpp index 3c4f2faa3..1b5a493f7 100644 --- a/nn/common/operations/Slice.cpp +++ b/nn/common/operations/Slice.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "Operations" #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "OperationResolver.h" @@ -37,8 +36,6 @@ constexpr uint32_t kSizeTensor = 2; constexpr uint32_t kNumOutputs = 1; constexpr uint32_t kOutputTensor = 0; -using namespace hal; - namespace { template <typename T> diff --git a/nn/common/operations/Softmax.cpp b/nn/common/operations/Softmax.cpp index a986390e1..bb85c0b66 100644 --- a/nn/common/operations/Softmax.cpp +++ b/nn/common/operations/Softmax.cpp @@ -25,7 +25,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" @@ -46,8 +45,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - inline bool softmaxSlowFloat32(const float* inputData, const Shape& inputShape, const float beta, int32_t axis, float* outputData, const Shape& outputShape) { NNTRACE_TRANS("softmaxFloatSlow32"); diff --git a/nn/common/operations/Squeeze.cpp b/nn/common/operations/Squeeze.cpp index 276461d1e..d7345505c 100644 --- a/nn/common/operations/Squeeze.cpp +++ b/nn/common/operations/Squeeze.cpp @@ -20,7 +20,6 @@ #include <vector> -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Operations.h" #include "Tracing.h" @@ -36,8 +35,6 @@ constexpr uint32_t kSqueezeDims = 1; constexpr uint32_t kNumOutputs = 1; constexpr uint32_t kOutputTensor = 0; -using namespace hal; - bool validate(const IOperationValidationContext* context) { NN_RET_CHECK_EQ(context->getNumInputs(), kNumInputs); NN_RET_CHECK_EQ(context->getNumOutputs(), kNumOutputs); @@ -46,7 +43,7 @@ bool validate(const IOperationValidationContext* context) { inputType == OperandType::TENSOR_FLOAT32 || inputType == OperandType::TENSOR_QUANT8_ASYMM || inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Unsupported input operand type for SQUEEZE op: " << toString(inputType); + << "Unsupported input operand type for SQUEEZE op: " << inputType; HalVersion minSupportedHalVersion; if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { diff --git a/nn/common/operations/StridedSlice.cpp b/nn/common/operations/StridedSlice.cpp index 5ff5aeca8..3bb3a829d 100644 --- a/nn/common/operations/StridedSlice.cpp +++ b/nn/common/operations/StridedSlice.cpp @@ -23,7 +23,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Operations.h" #include "Tracing.h" @@ -46,8 +45,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> bool compute(const T* inputData, const Shape& inputShape, const int32_t* beginData, const int32_t* endData, const int32_t* stridesData, int32_t beginMask, int32_t endMask, @@ -107,7 +104,7 @@ bool validate(const IOperationValidationContext* context) { inputType == OperandType::TENSOR_FLOAT32 || inputType == OperandType::TENSOR_QUANT8_ASYMM || inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Unsupported input operand type for STRIDED_SLICE op: " << toString(inputType); + << "Unsupported input operand type for STRIDED_SLICE op: " << inputType; HalVersion minSupportedHalVersion; if (inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) { diff --git a/nn/common/operations/Tile.cpp b/nn/common/operations/Tile.cpp index 517d75e7a..af17df1b9 100644 --- a/nn/common/operations/Tile.cpp +++ b/nn/common/operations/Tile.cpp @@ -20,7 +20,6 @@ #include <utility> #include "Tile.h" -#include "HalInterfaces.h" #include "Tracing.h" namespace android { @@ -29,8 +28,6 @@ namespace tile { namespace { -using namespace hal; - template <typename T> void CopyMultipleTimes(const T* in_data, int32_t in_size, int32_t multiplier, T* out_data) { for (int i = 0; i < multiplier; ++i) { diff --git a/nn/common/operations/TopK_V2.cpp b/nn/common/operations/TopK_V2.cpp index e005b9a33..9e4ceeda8 100644 --- a/nn/common/operations/TopK_V2.cpp +++ b/nn/common/operations/TopK_V2.cpp @@ -20,7 +20,6 @@ #include <utility> #include <vector> -#include "HalInterfaces.h" #include "OperationResolver.h" #include "OperationsUtils.h" @@ -38,8 +37,6 @@ constexpr uint32_t kOutputIndicesTensor = 1; namespace { -using namespace hal; - template <typename T> bool evalGeneric(const T* inputData, const Shape& inputShape, const int32_t k, T* valuesData, int32_t* indicesData) { @@ -85,7 +82,7 @@ bool validate(const IOperationValidationContext* context) { inputType == OperandType::TENSOR_INT32 || inputType == OperandType::TENSOR_QUANT8_ASYMM || inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) - << "Unsupported input operand type for select op: " << toString(inputType); + << "Unsupported input operand type for select op: " << inputType; NN_RET_CHECK(validateInputTypes(context, {inputType, OperandType::INT32})); NN_RET_CHECK(validateOutputTypes(context, {inputType, OperandType::TENSOR_INT32})); HalVersion minSupportedHalVersion = HalVersion::V1_2; @@ -132,7 +129,7 @@ bool execute(IOperationExecutionContext* context) { return executeTyped<int8_t>(context); } break; default: { - LOG(ERROR) << "Unsupported data type: " << toString(inputShape.type); + LOG(ERROR) << "Unsupported data type: " << inputShape.type; return false; } } diff --git a/nn/common/operations/Transpose.cpp b/nn/common/operations/Transpose.cpp index ff70f9e8b..423b3ded6 100644 --- a/nn/common/operations/Transpose.cpp +++ b/nn/common/operations/Transpose.cpp @@ -19,7 +19,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include <tensorflow/lite/kernels/internal/optimized/legacy_optimized_ops.h> @@ -42,8 +41,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - template <typename T> bool transposeGeneric(const T* inputData, const Shape& inputShape, const int32_t* perm, const Shape& permShape, T* outputData, const Shape& outputShape) { diff --git a/nn/common/operations/TransposeConv2D.cpp b/nn/common/operations/TransposeConv2D.cpp index d67a473e6..0ee5d044c 100644 --- a/nn/common/operations/TransposeConv2D.cpp +++ b/nn/common/operations/TransposeConv2D.cpp @@ -25,7 +25,6 @@ #include <vector> #include "CpuOperationUtils.h" -#include "HalInterfaces.h" #include "OperationResolver.h" #include "Tracing.h" @@ -46,8 +45,6 @@ constexpr uint32_t kOutputTensor = 0; namespace { -using namespace hal; - // If possible we will use this static buffer for the tensor. constexpr size_t kStaticBufferSize = 1605632; char static_scratch_buffer[kStaticBufferSize]; @@ -452,7 +449,9 @@ bool validate(const IOperationValidationContext* context) { filterType == inputType) << "Unsupported filter tensor type for operation " << kOperationName; if (filterType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { - NN_RET_CHECK_EQ(context->getInputExtraParams(kFilterTensor).channelQuant().channelDim, + NN_RET_CHECK_EQ(std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .channelDim, 0) << "Unsupported filter tensor channel dimension for operation " << kOperationName; @@ -570,7 +569,9 @@ bool execute(IOperationExecutionContext* context) { context->getInputShape(kInputTensor), context->getInputBuffer<int8_t>(kFilterTensor), context->getInputShape(kFilterTensor), - context->getInputExtraParams(kFilterTensor).channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .scales.data(), context->getInputBuffer<int32_t>(kBiasTensor), context->getInputShape(kBiasTensor), param, context->getOutputBuffer<uint8_t>(kOutputTensor), @@ -595,7 +596,9 @@ bool execute(IOperationExecutionContext* context) { context->getInputShape(kInputTensor), context->getInputBuffer<int8_t>(kFilterTensor), context->getInputShape(kFilterTensor), - context->getInputExtraParams(kFilterTensor).channelQuant().scales.data(), + std::get<Operand::SymmPerChannelQuantParams>( + context->getInputExtraParams(kFilterTensor)) + .scales.data(), context->getInputBuffer<int32_t>(kBiasTensor), context->getInputShape(kBiasTensor), param, context->getOutputBuffer<int8_t>(kOutputTensor), diff --git a/nn/common/operations/UnidirectionalSequenceLSTM.cpp b/nn/common/operations/UnidirectionalSequenceLSTM.cpp index 03854f65f..9a00e1f01 100644 --- a/nn/common/operations/UnidirectionalSequenceLSTM.cpp +++ b/nn/common/operations/UnidirectionalSequenceLSTM.cpp @@ -18,7 +18,6 @@ #include <vector> -#include "HalInterfaces.h" #include "IndexedShapeWrapper.h" #include "LSTM.h" #include "OperationResolver.h" @@ -88,8 +87,6 @@ constexpr uint32_t kCellStateOutTensor = 2; namespace { -using namespace hal; - inline bool hasTensor(IOperationExecutionContext* context, const uint32_t tensor) { return context->getInputBuffer(tensor) != nullptr; } @@ -157,7 +154,7 @@ bool validate(const IOperationValidationContext* context) { } else { NN_RET_CHECK_FAIL() << "Unsupported input operand type for UNIDIRECTIONAL_SEQUENCE_LSTM op: " - << toString(inputType); + << inputType; } HalVersion minHalVersionSupported = HalVersion::V1_2; if (context->getNumOutputs() == kNumOutputsWithState) { diff --git a/nn/common/operations/UnidirectionalSequenceRNN.cpp b/nn/common/operations/UnidirectionalSequenceRNN.cpp index 273b7017a..aa79739ec 100644 --- a/nn/common/operations/UnidirectionalSequenceRNN.cpp +++ b/nn/common/operations/UnidirectionalSequenceRNN.cpp @@ -20,9 +20,9 @@ #include <utility> #include <vector> -#include "HalInterfaces.h" #include "OperationResolver.h" #include "RNN.h" +#include "nnapi/TypeUtils.h" namespace android { namespace nn { @@ -44,8 +44,6 @@ constexpr uint32_t kStateOutputTensor = 1; namespace { -using namespace hal; - template <typename T> void transposeFirstTwoDims(const T* input, const Shape& inputShape, T* output) { const uint32_t firstDimSize = getSizeOfDimension(inputShape, 0); @@ -135,7 +133,7 @@ bool validate(const IOperationValidationContext* context) { OperandType inputType = context->getInputType(kInputTensor); if (inputType != OperandType::TENSOR_FLOAT16 && inputType != OperandType::TENSOR_FLOAT32) { LOG(ERROR) << "Unsupported input operand type for UNIDIRECTIONAL_SEQUENCE_RNN op: " - << toString(inputType); + << inputType; return false; } NN_RET_CHECK(validateInputTypes(context, {inputType, inputType, inputType, inputType, inputType, diff --git a/nn/driver/sample/SampleDriver.cpp b/nn/driver/sample/SampleDriver.cpp index b6303acd1..61e2b8bfb 100644 --- a/nn/driver/sample/SampleDriver.cpp +++ b/nn/driver/sample/SampleDriver.cpp @@ -47,8 +47,6 @@ namespace sample_driver { namespace { -using namespace hal; - using time_point = std::chrono::steady_clock::time_point; auto now() { @@ -61,174 +59,185 @@ auto microsecondsDuration(decltype(now()) end, decltype(now()) start) { } // namespace -static const Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; +static const V1_2::Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; -Return<void> SampleDriver::getCapabilities(getCapabilities_cb cb) { +hardware::Return<void> SampleDriver::getCapabilities(getCapabilities_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INITIALIZATION, "SampleDriver::getCapabilities"); - return getCapabilities_1_3([&](ErrorStatus error, const V1_3::Capabilities& capabilities) { - // TODO(dgross): Do we need to check compliantWithV1_0(capabilities)? - cb(convertToV1_0(error), convertToV1_0(capabilities)); - }); + return getCapabilities_1_3( + [&](V1_3::ErrorStatus error, const V1_3::Capabilities& capabilities) { + // TODO(dgross): Do we need to check compliantWithV1_0(capabilities)? + cb(convertToV1_0(error), convertToV1_0(capabilities)); + }); } -Return<void> SampleDriver::getCapabilities_1_1(getCapabilities_1_1_cb cb) { +hardware::Return<void> SampleDriver::getCapabilities_1_1(getCapabilities_1_1_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INITIALIZATION, "SampleDriver::getCapabilities_1_1"); - return getCapabilities_1_3([&](ErrorStatus error, const V1_3::Capabilities& capabilities) { - // TODO(dgross): Do we need to check compliantWithV1_1(capabilities)? - cb(convertToV1_0(error), convertToV1_1(capabilities)); - }); + return getCapabilities_1_3( + [&](V1_3::ErrorStatus error, const V1_3::Capabilities& capabilities) { + // TODO(dgross): Do we need to check compliantWithV1_1(capabilities)? + cb(convertToV1_0(error), convertToV1_1(capabilities)); + }); } -Return<void> SampleDriver::getCapabilities_1_2(getCapabilities_1_2_cb cb) { +hardware::Return<void> SampleDriver::getCapabilities_1_2(getCapabilities_1_2_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INITIALIZATION, "SampleDriver::getCapabilities_1_2"); - return getCapabilities_1_3([&](ErrorStatus error, const V1_3::Capabilities& capabilities) { - // TODO(dgross): Do we need to check compliantWithV1_2(capabilities)? - cb(convertToV1_0(error), convertToV1_2(capabilities)); - }); + return getCapabilities_1_3( + [&](V1_3::ErrorStatus error, const V1_3::Capabilities& capabilities) { + // TODO(dgross): Do we need to check compliantWithV1_2(capabilities)? + cb(convertToV1_0(error), convertToV1_2(capabilities)); + }); } -Return<void> SampleDriver::getVersionString(getVersionString_cb cb) { +hardware::Return<void> SampleDriver::getVersionString(getVersionString_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INITIALIZATION, "SampleDriver::getVersionString"); cb(V1_0::ErrorStatus::NONE, "JUST_AN_EXAMPLE"); - return Void(); + return hardware::Void(); } -Return<void> SampleDriver::getType(getType_cb cb) { +hardware::Return<void> SampleDriver::getType(getType_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INITIALIZATION, "SampleDriver::getType"); cb(V1_0::ErrorStatus::NONE, V1_2::DeviceType::CPU); - return Void(); + return hardware::Void(); } -Return<void> SampleDriver::getSupportedExtensions(getSupportedExtensions_cb cb) { +hardware::Return<void> SampleDriver::getSupportedExtensions(getSupportedExtensions_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INITIALIZATION, "SampleDriver::getSupportedExtensions"); cb(V1_0::ErrorStatus::NONE, {/* No extensions. */}); - return Void(); + return hardware::Void(); } -Return<void> SampleDriver::getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb cb) { +hardware::Return<void> SampleDriver::getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::getSupportedOperations"); if (!validateModel(model)) { VLOG(DRIVER) << "getSupportedOperations"; cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}); - return Void(); + return hardware::Void(); } - return getSupportedOperations_1_3(convertToV1_3(model), - [&](ErrorStatus status, const hidl_vec<bool>& supported) { - cb(convertToV1_0(status), supported); - }); + return getSupportedOperations_1_3( + convertToV1_3(model), + [&](V1_3::ErrorStatus status, const hardware::hidl_vec<bool>& supported) { + cb(convertToV1_0(status), supported); + }); } -Return<void> SampleDriver::getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb cb) { +hardware::Return<void> SampleDriver::getSupportedOperations_1_1(const V1_1::Model& model, + getSupportedOperations_1_1_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::getSupportedOperations_1_1"); if (!validateModel(model)) { VLOG(DRIVER) << "getSupportedOperations_1_1"; cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}); - return Void(); + return hardware::Void(); } - return getSupportedOperations_1_3(convertToV1_3(model), - [&](ErrorStatus status, const hidl_vec<bool>& supported) { - cb(convertToV1_0(status), supported); - }); + return getSupportedOperations_1_3( + convertToV1_3(model), + [&](V1_3::ErrorStatus status, const hardware::hidl_vec<bool>& supported) { + cb(convertToV1_0(status), supported); + }); } -Return<void> SampleDriver::getSupportedOperations_1_2(const V1_2::Model& model, - getSupportedOperations_1_2_cb cb) { +hardware::Return<void> SampleDriver::getSupportedOperations_1_2(const V1_2::Model& model, + getSupportedOperations_1_2_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::getSupportedOperations_1_2"); if (!validateModel(model)) { VLOG(DRIVER) << "getSupportedOperations_1_2"; cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}); - return Void(); + return hardware::Void(); } - return getSupportedOperations_1_3(convertToV1_3(model), - [&](ErrorStatus status, const hidl_vec<bool>& supported) { - cb(convertToV1_0(status), supported); - }); + return getSupportedOperations_1_3( + convertToV1_3(model), + [&](V1_3::ErrorStatus status, const hardware::hidl_vec<bool>& supported) { + cb(convertToV1_0(status), supported); + }); } -Return<void> SampleDriver::getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) { +hardware::Return<void> SampleDriver::getNumberOfCacheFilesNeeded( + getNumberOfCacheFilesNeeded_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INITIALIZATION, "SampleDriver::getNumberOfCacheFilesNeeded"); // Set both numbers to be 0 for cache not supported. cb(V1_0::ErrorStatus::NONE, /*numModelCache=*/0, /*numDataCache=*/0); - return Void(); + return hardware::Void(); } -Return<V1_0::ErrorStatus> SampleDriver::prepareModel( +hardware::Return<V1_0::ErrorStatus> SampleDriver::prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::prepareModel"); - const ErrorStatus status = prepareModelBase( - model, this, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, {}, callback); + const V1_3::ErrorStatus status = + prepareModelBase(model, this, V1_1::ExecutionPreference::FAST_SINGLE_ANSWER, + kDefaultPriority13, {}, callback); return convertToV1_0(status); } -Return<V1_0::ErrorStatus> SampleDriver::prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, +hardware::Return<V1_0::ErrorStatus> SampleDriver::prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::prepareModel_1_1"); - const ErrorStatus status = - prepareModelBase(model, this, preference, kDefaultPriority, {}, callback); + const V1_3::ErrorStatus status = + prepareModelBase(model, this, preference, kDefaultPriority13, {}, callback); return convertToV1_0(status); } -Return<V1_0::ErrorStatus> SampleDriver::prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference preference, const hidl_vec<hidl_handle>&, - const hidl_vec<hidl_handle>&, const CacheToken&, +hardware::Return<V1_0::ErrorStatus> SampleDriver::prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const HalCacheToken&, const sp<V1_2::IPreparedModelCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::prepareModel_1_2"); - const ErrorStatus status = - prepareModelBase(model, this, preference, kDefaultPriority, {}, callback); + const V1_3::ErrorStatus status = + prepareModelBase(model, this, preference, kDefaultPriority13, {}, callback); return convertToV1_0(status); } -Return<V1_3::ErrorStatus> SampleDriver::prepareModel_1_3( - const V1_3::Model& model, ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>&, - const hidl_vec<hidl_handle>&, const CacheToken&, +hardware::Return<V1_3::ErrorStatus> SampleDriver::prepareModel_1_3( + const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const HalCacheToken&, const sp<V1_3::IPreparedModelCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::prepareModel_1_3"); return prepareModelBase(model, this, preference, priority, deadline, callback); } -Return<V1_0::ErrorStatus> SampleDriver::prepareModelFromCache( - const hidl_vec<hidl_handle>&, const hidl_vec<hidl_handle>&, const CacheToken&, +hardware::Return<V1_0::ErrorStatus> SampleDriver::prepareModelFromCache( + const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const HalCacheToken&, const sp<V1_2::IPreparedModelCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::prepareModelFromCache"); - notify(callback, ErrorStatus::GENERAL_FAILURE, nullptr); + notify(callback, V1_3::ErrorStatus::GENERAL_FAILURE, nullptr); return V1_0::ErrorStatus::GENERAL_FAILURE; } -Return<ErrorStatus> SampleDriver::prepareModelFromCache_1_3( - const OptionalTimePoint& /*deadline*/, const hidl_vec<hidl_handle>&, - const hidl_vec<hidl_handle>&, const CacheToken&, +hardware::Return<V1_3::ErrorStatus> SampleDriver::prepareModelFromCache_1_3( + const V1_3::OptionalTimePoint& /*deadline*/, + const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const HalCacheToken&, const sp<V1_3::IPreparedModelCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_COMPILATION, "SampleDriver::prepareModelFromCache_1_3"); - notify(callback, ErrorStatus::GENERAL_FAILURE, nullptr); - return ErrorStatus::GENERAL_FAILURE; + notify(callback, V1_3::ErrorStatus::GENERAL_FAILURE, nullptr); + return V1_3::ErrorStatus::GENERAL_FAILURE; } -Return<DeviceStatus> SampleDriver::getStatus() { +hardware::Return<V1_0::DeviceStatus> SampleDriver::getStatus() { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_UNSPECIFIED, "SampleDriver::getStatus"); VLOG(DRIVER) << "getStatus()"; - return DeviceStatus::AVAILABLE; + return V1_0::DeviceStatus::AVAILABLE; } // Safely downcast an IPreparedModel object to SamplePreparedModel. // This function will return nullptr if the IPreparedModel object is not originated from the sample // driver process. static const SamplePreparedModel* castToSamplePreparedModel( - const sp<IPreparedModel>& preparedModel) { + const sp<V1_3::IPreparedModel>& preparedModel) { if (preparedModel->isRemote()) { return nullptr; } else { @@ -238,10 +247,11 @@ static const SamplePreparedModel* castToSamplePreparedModel( } } -Return<void> SampleDriver::allocate(const V1_3::BufferDesc& desc, - const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, - const hidl_vec<V1_3::BufferRole>& inputRoles, - const hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) { +hardware::Return<void> SampleDriver::allocate( + const V1_3::BufferDesc& desc, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, + const hardware::hidl_vec<V1_3::BufferRole>& inputRoles, + const hardware::hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) { constexpr uint32_t kInvalidBufferToken = 0; VLOG(DRIVER) << "SampleDriver::allocate"; @@ -258,14 +268,14 @@ Return<void> SampleDriver::allocate(const V1_3::BufferDesc& desc, if (!validateMemoryDesc(desc, preparedModels, inputRoles, outputRoles, getModel, &roles, &operand)) { LOG(ERROR) << "SampleDriver::allocate -- validation failed."; - cb(ErrorStatus::INVALID_ARGUMENT, nullptr, kInvalidBufferToken); - return Void(); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr, kInvalidBufferToken); + return hardware::Void(); } if (isExtensionOperandType(operand.type)) { LOG(ERROR) << "SampleDriver::allocate -- does not support extension type."; - cb(ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); + return hardware::Void(); } // TODO(xusongw): Support allocating buffers with unknown dimensions or rank. @@ -274,29 +284,29 @@ Return<void> SampleDriver::allocate(const V1_3::BufferDesc& desc, << ", dimensions = " << toString(operand.dimensions) << ", size = " << size; if (size == 0) { LOG(ERROR) << "SampleDriver::allocate -- does not support dynamic output shape."; - cb(ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); + return hardware::Void(); } - auto bufferWrapper = ManagedBuffer::create(size, std::move(roles), std::move(operand)); + auto bufferWrapper = ManagedBuffer::create(size, std::move(roles), uncheckedConvert(operand)); if (bufferWrapper == nullptr) { LOG(ERROR) << "SampleDriver::allocate -- not enough memory."; - cb(ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); + return hardware::Void(); } auto token = mBufferTracker->add(bufferWrapper); if (token == nullptr) { LOG(ERROR) << "SampleDriver::allocate -- BufferTracker returned invalid token."; - cb(ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, kInvalidBufferToken); + return hardware::Void(); } const uint32_t tokenValue = token->get(); sp<SampleBuffer> sampleBuffer = new SampleBuffer(std::move(bufferWrapper), std::move(token)); VLOG(DRIVER) << "SampleDriver::allocate -- successfully allocates the requested memory"; - cb(ErrorStatus::NONE, std::move(sampleBuffer), tokenValue); - return Void(); + cb(V1_3::ErrorStatus::NONE, std::move(sampleBuffer), tokenValue); + return hardware::Void(); } int SampleDriver::run() { @@ -318,43 +328,45 @@ static void copyRunTimePoolInfos(const RunTimePoolInfo& srcPool, const RunTimePo dstPool.flush(); } -Return<ErrorStatus> SampleBuffer::copyTo(const hidl_memory& dst) { - const auto dstPool = RunTimePoolInfo::createFromHidlMemory(dst); +hardware::Return<V1_3::ErrorStatus> SampleBuffer::copyTo(const hardware::hidl_memory& dst) { + const auto dstPool = RunTimePoolInfo::createFromMemory(uncheckedConvert(dst)); if (!dstPool.has_value()) { LOG(ERROR) << "SampleBuffer::copyTo -- unable to map dst memory."; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } - const ErrorStatus validationStatus = kBuffer->validateCopyTo(dstPool->getSize()); - if (validationStatus != ErrorStatus::NONE) { + const V1_3::ErrorStatus validationStatus = + convertToV1_3(kBuffer->validateCopyTo(dstPool->getSize())); + if (validationStatus != V1_3::ErrorStatus::NONE) { return validationStatus; } const auto srcPool = kBuffer->createRunTimePoolInfo(); copyRunTimePoolInfos(srcPool, dstPool.value()); - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } -static ErrorStatus copyFromInternal(const hidl_memory& src, const hidl_vec<uint32_t>& dimensions, - const std::shared_ptr<ManagedBuffer>& bufferWrapper) { +static V1_3::ErrorStatus copyFromInternal(const hardware::hidl_memory& src, + const hardware::hidl_vec<uint32_t>& dimensions, + const std::shared_ptr<ManagedBuffer>& bufferWrapper) { CHECK(bufferWrapper != nullptr); - const auto srcPool = RunTimePoolInfo::createFromHidlMemory(src); + const auto srcPool = RunTimePoolInfo::createFromMemory(uncheckedConvert(src)); if (!srcPool.has_value()) { LOG(ERROR) << "SampleBuffer::copyFrom -- unable to map src memory."; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } - const ErrorStatus validationStatus = - bufferWrapper->validateCopyFrom(dimensions, srcPool->getSize()); - if (validationStatus != ErrorStatus::NONE) { + const V1_3::ErrorStatus validationStatus = + convertToV1_3(bufferWrapper->validateCopyFrom(dimensions, srcPool->getSize())); + if (validationStatus != V1_3::ErrorStatus::NONE) { return validationStatus; } const auto dstPool = bufferWrapper->createRunTimePoolInfo(); copyRunTimePoolInfos(srcPool.value(), dstPool); - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } -Return<ErrorStatus> SampleBuffer::copyFrom(const hidl_memory& src, - const hidl_vec<uint32_t>& dimensions) { +hardware::Return<V1_3::ErrorStatus> SampleBuffer::copyFrom( + const hardware::hidl_memory& src, const hardware::hidl_vec<uint32_t>& dimensions) { const auto status = copyFromInternal(src, dimensions, kBuffer); - if (status == ErrorStatus::NONE) { + if (status == V1_3::ErrorStatus::NONE) { kBuffer->updateDimensions(dimensions); kBuffer->setInitialized(true); } else { @@ -364,12 +376,12 @@ Return<ErrorStatus> SampleBuffer::copyFrom(const hidl_memory& src, } bool SamplePreparedModel::initialize() { - return setRunTimePoolInfosFromHidlMemories(&mPoolInfos, mModel.pools); + return setRunTimePoolInfosFromCanonicalMemories(&mPoolInfos, uncheckedConvert(mModel.pools)); } -static std::tuple<ErrorStatus, std::vector<RunTimePoolInfo>, +static std::tuple<V1_3::ErrorStatus, std::vector<RunTimePoolInfo>, std::vector<std::shared_ptr<ManagedBuffer>>> -createRunTimePoolInfos(const Request& request, const SampleDriver& driver, +createRunTimePoolInfos(const V1_3::Request& request, const SampleDriver& driver, const SamplePreparedModel* preparedModel) { std::vector<RunTimePoolInfo> requestPoolInfos; std::vector<std::shared_ptr<ManagedBuffer>> bufferWrappers; @@ -378,23 +390,24 @@ createRunTimePoolInfos(const Request& request, const SampleDriver& driver, for (uint32_t i = 0; i < request.pools.size(); i++) { auto& pool = request.pools[i]; switch (pool.getDiscriminator()) { - case Request::MemoryPool::hidl_discriminator::hidlMemory: { - auto buffer = RunTimePoolInfo::createFromHidlMemory(pool.hidlMemory()); + case V1_3::Request::MemoryPool::hidl_discriminator::hidlMemory: { + auto buffer = + RunTimePoolInfo::createFromMemory(uncheckedConvert(pool.hidlMemory())); if (!buffer.has_value()) { LOG(ERROR) << "createRuntimeMemoriesFromMemoryPools -- could not map pools"; - return {ErrorStatus::GENERAL_FAILURE, {}, {}}; + return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, {}}; } requestPoolInfos.push_back(std::move(*buffer)); bufferWrappers.push_back(nullptr); } break; - case Request::MemoryPool::hidl_discriminator::token: { + case V1_3::Request::MemoryPool::hidl_discriminator::token: { auto bufferWrapper = driver.getBufferTracker()->get(pool.token()); if (bufferWrapper == nullptr) { - return {ErrorStatus::INVALID_ARGUMENT, {}, {}}; + return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, {}}; } - const auto validationStatus = - bufferWrapper->validateRequest(i, request, preparedModel); - if (validationStatus != ErrorStatus::NONE) { + const auto validationStatus = convertToV1_3(bufferWrapper->validateRequest( + i, uncheckedConvert(request), preparedModel)); + if (validationStatus != V1_3::ErrorStatus::NONE) { return {validationStatus, {}, {}}; } requestPoolInfos.push_back(bufferWrapper->createRunTimePoolInfo()); @@ -402,63 +415,63 @@ createRunTimePoolInfos(const Request& request, const SampleDriver& driver, } break; } } - return {ErrorStatus::NONE, std::move(requestPoolInfos), std::move(bufferWrappers)}; + return {V1_3::ErrorStatus::NONE, std::move(requestPoolInfos), std::move(bufferWrappers)}; } -static ErrorStatus updateDeviceMemories( - ErrorStatus status, const Request& request, +static V1_3::ErrorStatus updateDeviceMemories( + V1_3::ErrorStatus status, const V1_3::Request& request, const std::vector<std::shared_ptr<ManagedBuffer>>& bufferWrappers, - const hidl_vec<OutputShape>& outputShapes) { - if (status == ErrorStatus::NONE) { + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes) { + if (status == V1_3::ErrorStatus::NONE) { for (uint32_t i = 0; i < request.outputs.size(); i++) { const uint32_t poolIndex = request.outputs[i].location.poolIndex; const auto& pool = request.pools[poolIndex]; - if (pool.getDiscriminator() == Request::MemoryPool::hidl_discriminator::token) { + if (pool.getDiscriminator() == V1_3::Request::MemoryPool::hidl_discriminator::token) { if (!bufferWrappers[poolIndex]->updateDimensions(outputShapes[i].dimensions)) { - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } } for (uint32_t i = 0; i < request.outputs.size(); i++) { const uint32_t poolIndex = request.outputs[i].location.poolIndex; const auto& pool = request.pools[poolIndex]; - if (pool.getDiscriminator() == Request::MemoryPool::hidl_discriminator::token) { + if (pool.getDiscriminator() == V1_3::Request::MemoryPool::hidl_discriminator::token) { bufferWrappers[poolIndex]->setInitialized(true); } } - } else if (status == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + } else if (status == V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { // If CpuExecutor reports OUTPUT_INSUFFCIENT_SIZE on a device memory, this is because the // dimensions of the device memory are incorrectly specified. The driver should return // GENERAL_FAILURE instead in this case. for (uint32_t i = 0; i < request.outputs.size(); i++) { const uint32_t poolIndex = request.outputs[i].location.poolIndex; const auto& pool = request.pools[poolIndex]; - if (pool.getDiscriminator() == Request::MemoryPool::hidl_discriminator::token) { + if (pool.getDiscriminator() == V1_3::Request::MemoryPool::hidl_discriminator::token) { if (!outputShapes[i].isSufficient) { LOG(ERROR) << "Invalid dimensions for output " << i << ": actual shape = " << toString(outputShapes[i].dimensions); - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } template <typename T_IExecutionCallback> -void asyncExecute(const Request& request, MeasureTiming measure, time_point driverStart, - const Model& model, const SampleDriver& driver, +void asyncExecute(const V1_3::Request& request, V1_2::MeasureTiming measure, time_point driverStart, + const V1_3::Model& model, const SampleDriver& driver, const SamplePreparedModel* preparedModel, const std::vector<RunTimePoolInfo>& poolInfos, const std::optional<Deadline>& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, const sp<T_IExecutionCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INPUTS_AND_OUTPUTS, "SampleDriver::asyncExecute"); const auto [poolStatus, requestPoolInfos, bufferWrappers] = createRunTimePoolInfos(request, driver, preparedModel); - if (poolStatus != ErrorStatus::NONE) { + if (poolStatus != V1_3::ErrorStatus::NONE) { notify(callback, poolStatus, {}, kNoTiming); return; } @@ -467,32 +480,34 @@ void asyncExecute(const Request& request, MeasureTiming measure, time_point driv "SampleDriver::asyncExecute"); CpuExecutor executor = driver.getExecutor(); if (loopTimeoutDuration.getDiscriminator() != - OptionalTimeoutDuration::hidl_discriminator::none) { + V1_3::OptionalTimeoutDuration::hidl_discriminator::none) { executor.setLoopTimeout(loopTimeoutDuration.nanoseconds()); } if (deadline.has_value()) { executor.setDeadline(*deadline); } time_point driverEnd, deviceStart, deviceEnd; - if (measure == MeasureTiming::YES) deviceStart = now(); - int n = executor.run(model, request, poolInfos, requestPoolInfos); - if (measure == MeasureTiming::YES) deviceEnd = now(); + if (measure == V1_2::MeasureTiming::YES) deviceStart = now(); + int n = executor.run(uncheckedConvert(model), uncheckedConvert(request), poolInfos, + requestPoolInfos); + if (measure == V1_2::MeasureTiming::YES) deviceEnd = now(); VLOG(DRIVER) << "executor.run returned " << n; - ErrorStatus executionStatus = convertResultCodeToErrorStatus(n); - hidl_vec<OutputShape> outputShapes = executor.getOutputShapes(); + V1_3::ErrorStatus executionStatus = convertResultCodeToHalErrorStatus(n); + hardware::hidl_vec<V1_2::OutputShape> outputShapes = convertToV1_2(executor.getOutputShapes()); // Update device memory metadata. - const ErrorStatus updateStatus = + const V1_3::ErrorStatus updateStatus = updateDeviceMemories(executionStatus, request, bufferWrappers, outputShapes); - if (updateStatus != ErrorStatus::NONE) { + if (updateStatus != V1_3::ErrorStatus::NONE) { notify(callback, updateStatus, {}, kNoTiming); return; } - if (measure == MeasureTiming::YES && executionStatus == ErrorStatus::NONE) { + if (measure == V1_2::MeasureTiming::YES && executionStatus == V1_3::ErrorStatus::NONE) { driverEnd = now(); - Timing timing = {.timeOnDevice = uint64_t(microsecondsDuration(deviceEnd, deviceStart)), - .timeInDriver = uint64_t(microsecondsDuration(driverEnd, driverStart))}; + V1_2::Timing timing = { + .timeOnDevice = uint64_t(microsecondsDuration(deviceEnd, deviceStart)), + .timeInDriver = uint64_t(microsecondsDuration(driverEnd, driverStart))}; VLOG(DRIVER) << "SampleDriver::asyncExecute timing = " << toString(timing); notify(callback, executionStatus, outputShapes, timing); } else { @@ -501,30 +516,31 @@ void asyncExecute(const Request& request, MeasureTiming measure, time_point driv } template <typename T_IExecutionCallback> -ErrorStatus executeBase(const Request& request, MeasureTiming measure, const Model& model, - const SampleDriver& driver, const SamplePreparedModel* preparedModel, - const std::vector<RunTimePoolInfo>& poolInfos, - const OptionalTimePoint& halDeadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const sp<T_IExecutionCallback>& callback) { +V1_3::ErrorStatus executeBase(const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::Model& model, const SampleDriver& driver, + const SamplePreparedModel* preparedModel, + const std::vector<RunTimePoolInfo>& poolInfos, + const V1_3::OptionalTimePoint& halDeadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const sp<T_IExecutionCallback>& callback) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION, "SampleDriver::executeBase"); VLOG(DRIVER) << "executeBase(" << SHOW_IF_DEBUG(toString(request)) << ")"; time_point driverStart; - if (measure == MeasureTiming::YES) driverStart = now(); + if (measure == V1_2::MeasureTiming::YES) driverStart = now(); if (callback.get() == nullptr) { LOG(ERROR) << "invalid callback passed to executeBase"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (!validateRequest(request, model)) { - notify(callback, ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming); - return ErrorStatus::INVALID_ARGUMENT; + notify(callback, V1_3::ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming); + return V1_3::ErrorStatus::INVALID_ARGUMENT; } const auto deadline = makeDeadline(halDeadline); if (hasDeadlinePassed(deadline)) { - notify(callback, ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming); - return ErrorStatus::NONE; + notify(callback, V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming); + return V1_3::ErrorStatus::NONE; } // This thread is intentionally detached because the sample driver service @@ -535,57 +551,61 @@ ErrorStatus executeBase(const Request& request, MeasureTiming measure, const Mod deadline, loopTimeoutDuration, callback); }).detach(); - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } -Return<V1_0::ErrorStatus> SamplePreparedModel::execute( +hardware::Return<V1_0::ErrorStatus> SamplePreparedModel::execute( const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) { - const ErrorStatus status = executeBase(convertToV1_3(request), MeasureTiming::NO, mModel, - *mDriver, this, mPoolInfos, {}, {}, callback); + const V1_3::ErrorStatus status = + executeBase(convertToV1_3(request), V1_2::MeasureTiming::NO, mModel, *mDriver, this, + mPoolInfos, {}, {}, callback); return convertToV1_0(status); } -Return<V1_0::ErrorStatus> SamplePreparedModel::execute_1_2( - const V1_0::Request& request, MeasureTiming measure, +hardware::Return<V1_0::ErrorStatus> SamplePreparedModel::execute_1_2( + const V1_0::Request& request, V1_2::MeasureTiming measure, const sp<V1_2::IExecutionCallback>& callback) { - const ErrorStatus status = executeBase(convertToV1_3(request), measure, mModel, *mDriver, this, - mPoolInfos, {}, {}, callback); + const V1_3::ErrorStatus status = executeBase(convertToV1_3(request), measure, mModel, *mDriver, + this, mPoolInfos, {}, {}, callback); return convertToV1_0(status); } -Return<V1_3::ErrorStatus> SamplePreparedModel::execute_1_3( - const V1_3::Request& request, MeasureTiming measure, const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, +hardware::Return<V1_3::ErrorStatus> SamplePreparedModel::execute_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, const sp<V1_3::IExecutionCallback>& callback) { return executeBase(request, measure, mModel, *mDriver, this, mPoolInfos, deadline, loopTimeoutDuration, callback); } -static std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> executeSynchronouslyBase( - const Request& request, MeasureTiming measure, const Model& model, - const SampleDriver& driver, const SamplePreparedModel* preparedModel, - const std::vector<RunTimePoolInfo>& poolInfos, const OptionalTimePoint& halDeadline, - const OptionalTimeoutDuration& loopTimeoutDuration) { +static std::tuple<V1_3::ErrorStatus, hardware::hidl_vec<V1_2::OutputShape>, V1_2::Timing> +executeSynchronouslyBase(const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::Model& model, const SampleDriver& driver, + const SamplePreparedModel* preparedModel, + const std::vector<RunTimePoolInfo>& poolInfos, + const V1_3::OptionalTimePoint& halDeadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION, "SampleDriver::executeSynchronouslyBase"); VLOG(DRIVER) << "executeSynchronouslyBase(" << SHOW_IF_DEBUG(toString(request)) << ")"; time_point driverStart, driverEnd, deviceStart, deviceEnd; - if (measure == MeasureTiming::YES) driverStart = now(); + if (measure == V1_2::MeasureTiming::YES) driverStart = now(); if (!validateRequest(request, model)) { - return {ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming}; + return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming}; } const auto deadline = makeDeadline(halDeadline); if (hasDeadlinePassed(deadline)) { - return {ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming}; + return {V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming}; } NNTRACE_FULL_SWITCH(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INPUTS_AND_OUTPUTS, "SampleDriver::executeSynchronouslyBase"); const auto [poolStatus, requestPoolInfos, bufferWrappers] = createRunTimePoolInfos(request, driver, preparedModel); - if (poolStatus != ErrorStatus::NONE) { + if (poolStatus != V1_3::ErrorStatus::NONE) { return {poolStatus, {}, kNoTiming}; } @@ -593,93 +613,97 @@ static std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> executeSynchronous "SampleDriver::executeSynchronouslyBase"); CpuExecutor executor = driver.getExecutor(); if (loopTimeoutDuration.getDiscriminator() != - OptionalTimeoutDuration::hidl_discriminator::none) { + V1_3::OptionalTimeoutDuration::hidl_discriminator::none) { executor.setLoopTimeout(loopTimeoutDuration.nanoseconds()); } if (deadline.has_value()) { executor.setDeadline(*deadline); } - if (measure == MeasureTiming::YES) deviceStart = now(); - int n = executor.run(model, request, poolInfos, requestPoolInfos); - if (measure == MeasureTiming::YES) deviceEnd = now(); + if (measure == V1_2::MeasureTiming::YES) deviceStart = now(); + int n = executor.run(uncheckedConvert(model), uncheckedConvert(request), poolInfos, + requestPoolInfos); + if (measure == V1_2::MeasureTiming::YES) deviceEnd = now(); VLOG(DRIVER) << "executor.run returned " << n; - ErrorStatus executionStatus = convertResultCodeToErrorStatus(n); - hidl_vec<OutputShape> outputShapes = executor.getOutputShapes(); + V1_3::ErrorStatus executionStatus = convertResultCodeToHalErrorStatus(n); + hardware::hidl_vec<V1_2::OutputShape> outputShapes = convertToV1_2(executor.getOutputShapes()); // Update device memory metadata. - const ErrorStatus updateStatus = + const V1_3::ErrorStatus updateStatus = updateDeviceMemories(executionStatus, request, bufferWrappers, outputShapes); - if (updateStatus != ErrorStatus::NONE) { + if (updateStatus != V1_3::ErrorStatus::NONE) { return {updateStatus, {}, kNoTiming}; } - if (measure == MeasureTiming::YES && executionStatus == ErrorStatus::NONE) { + if (measure == V1_2::MeasureTiming::YES && executionStatus == V1_3::ErrorStatus::NONE) { driverEnd = now(); - Timing timing = {.timeOnDevice = uint64_t(microsecondsDuration(deviceEnd, deviceStart)), - .timeInDriver = uint64_t(microsecondsDuration(driverEnd, driverStart))}; + V1_2::Timing timing = { + .timeOnDevice = uint64_t(microsecondsDuration(deviceEnd, deviceStart)), + .timeInDriver = uint64_t(microsecondsDuration(driverEnd, driverStart))}; VLOG(DRIVER) << "executeSynchronouslyBase timing = " << toString(timing); return {executionStatus, std::move(outputShapes), timing}; } return {executionStatus, std::move(outputShapes), kNoTiming}; } -Return<void> SamplePreparedModel::executeSynchronously(const V1_0::Request& request, - MeasureTiming measure, - executeSynchronously_cb cb) { +hardware::Return<void> SamplePreparedModel::executeSynchronously(const V1_0::Request& request, + V1_2::MeasureTiming measure, + executeSynchronously_cb cb) { auto [status, outputShapes, timing] = executeSynchronouslyBase( convertToV1_3(request), measure, mModel, *mDriver, this, mPoolInfos, {}, {}); cb(convertToV1_0(status), std::move(outputShapes), timing); - return Void(); + return hardware::Void(); } -Return<void> SamplePreparedModel::executeSynchronously_1_3( - const V1_3::Request& request, MeasureTiming measure, const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb) { +hardware::Return<void> SamplePreparedModel::executeSynchronously_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb) { auto [status, outputShapes, timing] = executeSynchronouslyBase( request, measure, mModel, *mDriver, this, mPoolInfos, deadline, loopTimeoutDuration); cb(status, std::move(outputShapes), timing); - return Void(); + return hardware::Void(); } // The sample driver will finish the execution and then return. -Return<void> SamplePreparedModel::executeFenced( - const hal::Request& request, const hidl_vec<hidl_handle>& waitFor, MeasureTiming measure, - const OptionalTimePoint& halDeadline, const OptionalTimeoutDuration& loopTimeoutDuration, - const OptionalTimeoutDuration& duration, executeFenced_cb cb) { +hardware::Return<void> SamplePreparedModel::executeFenced( + const V1_3::Request& request, const hardware::hidl_vec<hardware::hidl_handle>& waitFor, + V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& halDeadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const V1_3::OptionalTimeoutDuration& duration, executeFenced_cb cb) { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION, "SamplePreparedModel::executeFenced"); VLOG(DRIVER) << "executeFenced(" << SHOW_IF_DEBUG(toString(request)) << ")"; time_point driverStart, driverEnd, deviceStart, deviceEnd; - if (measure == MeasureTiming::YES) driverStart = now(); + if (measure == V1_2::MeasureTiming::YES) driverStart = now(); if (!validateRequest(request, mModel, /*allowUnspecifiedOutput=*/false)) { - cb(ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } const auto deadline = makeDeadline(halDeadline); if (hasDeadlinePassed(deadline)) { - cb(ErrorStatus::MISSED_DEADLINE_PERSISTENT, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } // Wait for the dependent events to signal for (const auto& fenceHandle : waitFor) { if (!fenceHandle.getNativeHandle()) { - cb(ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } int syncFenceFd = fenceHandle.getNativeHandle()->data[0]; if (syncWait(syncFenceFd, -1) != FenceState::SIGNALED) { LOG(ERROR) << "syncWait failed"; - cb(ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } } // Update deadline if the timeout duration is closer than the deadline. auto closestDeadline = deadline; - if (duration.getDiscriminator() != OptionalTimeoutDuration::hidl_discriminator::none) { + if (duration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none) { const auto timeoutDurationDeadline = makeDeadline(duration.nanoseconds()); if (!closestDeadline.has_value() || *closestDeadline > timeoutDurationDeadline) { closestDeadline = timeoutDurationDeadline; @@ -687,51 +711,52 @@ Return<void> SamplePreparedModel::executeFenced( } time_point driverStartAfterFence; - if (measure == MeasureTiming::YES) driverStartAfterFence = now(); + if (measure == V1_2::MeasureTiming::YES) driverStartAfterFence = now(); NNTRACE_FULL_SWITCH(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_INPUTS_AND_OUTPUTS, "SamplePreparedModel::executeFenced"); const auto [poolStatus, requestPoolInfos, bufferWrappers] = createRunTimePoolInfos(request, *mDriver, this); - if (poolStatus != ErrorStatus::NONE) { - cb(poolStatus, hidl_handle(nullptr), nullptr); - return Void(); + if (poolStatus != V1_3::ErrorStatus::NONE) { + cb(poolStatus, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } NNTRACE_FULL_SWITCH(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION, "SamplePreparedModel::executeFenced"); CpuExecutor executor = mDriver->getExecutor(); if (loopTimeoutDuration.getDiscriminator() != - OptionalTimeoutDuration::hidl_discriminator::none) { + V1_3::OptionalTimeoutDuration::hidl_discriminator::none) { executor.setLoopTimeout(loopTimeoutDuration.nanoseconds()); } if (closestDeadline.has_value()) { executor.setDeadline(*closestDeadline); } - if (measure == MeasureTiming::YES) deviceStart = now(); - int n = executor.run(mModel, request, mPoolInfos, requestPoolInfos); - if (measure == MeasureTiming::YES) deviceEnd = now(); + if (measure == V1_2::MeasureTiming::YES) deviceStart = now(); + int n = executor.run(uncheckedConvert(mModel), uncheckedConvert(request), mPoolInfos, + requestPoolInfos); + if (measure == V1_2::MeasureTiming::YES) deviceEnd = now(); VLOG(DRIVER) << "executor.run returned " << n; - ErrorStatus executionStatus = convertResultCodeToErrorStatus(n); - if (executionStatus != ErrorStatus::NONE) { - cb(executionStatus, hidl_handle(nullptr), nullptr); - return Void(); + V1_3::ErrorStatus executionStatus = convertResultCodeToHalErrorStatus(n); + if (executionStatus != V1_3::ErrorStatus::NONE) { + cb(executionStatus, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } // Set output memories to the initialized state. - if (executionStatus == ErrorStatus::NONE) { + if (executionStatus == V1_3::ErrorStatus::NONE) { for (const auto& output : request.outputs) { const uint32_t poolIndex = output.location.poolIndex; const auto& pool = request.pools[poolIndex]; - if (pool.getDiscriminator() == Request::MemoryPool::hidl_discriminator::token) { + if (pool.getDiscriminator() == V1_3::Request::MemoryPool::hidl_discriminator::token) { bufferWrappers[poolIndex]->setInitialized(true); } } } - Timing timingSinceLaunch = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; - Timing timingAfterFence = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; - if (measure == MeasureTiming::YES) { + V1_2::Timing timingSinceLaunch = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; + V1_2::Timing timingAfterFence = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; + if (measure == V1_2::MeasureTiming::YES) { driverEnd = now(); timingSinceLaunch = { .timeOnDevice = uint64_t(microsecondsDuration(deviceEnd, deviceStart)), @@ -744,8 +769,8 @@ Return<void> SamplePreparedModel::executeFenced( } sp<SampleFencedExecutionCallback> fencedExecutionCallback = new SampleFencedExecutionCallback(timingSinceLaunch, timingAfterFence, executionStatus); - cb(executionStatus, hidl_handle(nullptr), fencedExecutionCallback); - return Void(); + cb(executionStatus, hardware::hidl_handle(nullptr), fencedExecutionCallback); + return hardware::Void(); } // BurstExecutorWithCache maps hidl_memory when it is first seen, and preserves @@ -755,7 +780,7 @@ Return<void> SamplePreparedModel::executeFenced( // unmapping the memory on each execution. class BurstExecutorWithCache : public ExecutionBurstServer::IBurstExecutorWithCache { public: - BurstExecutorWithCache(const Model& model, const SampleDriver* driver, + BurstExecutorWithCache(const V1_3::Model& model, const SampleDriver* driver, const std::vector<RunTimePoolInfo>& poolInfos) : mModel(model), mDriver(driver), mModelPoolInfos(poolInfos) {} @@ -764,20 +789,20 @@ class BurstExecutorWithCache : public ExecutionBurstServer::IBurstExecutorWithCa return (it != mMemoryCache.end()) && it->second.has_value(); } - void addCacheEntry(const hidl_memory& memory, int32_t slot) override { - mMemoryCache[slot] = RunTimePoolInfo::createFromHidlMemory(memory); + void addCacheEntry(const hardware::hidl_memory& memory, int32_t slot) override { + mMemoryCache[slot] = RunTimePoolInfo::createFromMemory(uncheckedConvert(memory)); } void removeCacheEntry(int32_t slot) override { mMemoryCache.erase(slot); } - std::tuple<V1_0::ErrorStatus, hidl_vec<OutputShape>, Timing> execute( + std::tuple<V1_0::ErrorStatus, hardware::hidl_vec<V1_2::OutputShape>, V1_2::Timing> execute( const V1_0::Request& request, const std::vector<int32_t>& slots, - MeasureTiming measure) override { + V1_2::MeasureTiming measure) override { NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION, "BurstExecutorWithCache::execute"); time_point driverStart, driverEnd, deviceStart, deviceEnd; - if (measure == MeasureTiming::YES) driverStart = now(); + if (measure == V1_2::MeasureTiming::YES) driverStart = now(); // ensure all relevant pools are valid if (!std::all_of(slots.begin(), slots.end(), @@ -786,13 +811,13 @@ class BurstExecutorWithCache : public ExecutionBurstServer::IBurstExecutorWithCa } // finish the request object (for validation) - hidl_vec<Request::MemoryPool> pools(slots.size()); + hardware::hidl_vec<V1_3::Request::MemoryPool> pools(slots.size()); std::transform(slots.begin(), slots.end(), pools.begin(), [this](int32_t slot) { - Request::MemoryPool pool; - pool.hidlMemory(mMemoryCache[slot]->getHidlMemory()); + V1_3::Request::MemoryPool pool; + pool.hidlMemory(convertToV1_0(mMemoryCache[slot]->getMemory())); return pool; }); - Request fullRequest = {.inputs = request.inputs, .outputs = request.outputs}; + V1_3::Request fullRequest = {.inputs = request.inputs, .outputs = request.outputs}; fullRequest.pools = std::move(pools); // validate request object against the model @@ -811,15 +836,17 @@ class BurstExecutorWithCache : public ExecutionBurstServer::IBurstExecutorWithCa // because burst does not support HAL 1.3 and hence does not support // WHILE loops. CpuExecutor executor = mDriver->getExecutor(); - if (measure == MeasureTiming::YES) deviceStart = now(); - int n = executor.run(mModel, fullRequest, mModelPoolInfos, requestPoolInfos); - if (measure == MeasureTiming::YES) deviceEnd = now(); + if (measure == V1_2::MeasureTiming::YES) deviceStart = now(); + int n = executor.run(uncheckedConvert(mModel), uncheckedConvert(fullRequest), + mModelPoolInfos, requestPoolInfos); + if (measure == V1_2::MeasureTiming::YES) deviceEnd = now(); VLOG(DRIVER) << "executor.run returned " << n; - V1_0::ErrorStatus executionStatus = convertToV1_0(convertResultCodeToErrorStatus(n)); - hidl_vec<OutputShape> outputShapes = executor.getOutputShapes(); - if (measure == MeasureTiming::YES && executionStatus == V1_0::ErrorStatus::NONE) { + V1_0::ErrorStatus executionStatus = convertToV1_0(convertResultCodeToHalErrorStatus(n)); + hardware::hidl_vec<V1_2::OutputShape> outputShapes = + convertToV1_2(executor.getOutputShapes()); + if (measure == V1_2::MeasureTiming::YES && executionStatus == V1_0::ErrorStatus::NONE) { driverEnd = now(); - Timing timing = { + V1_2::Timing timing = { .timeOnDevice = uint64_t(microsecondsDuration(deviceEnd, deviceStart)), .timeInDriver = uint64_t(microsecondsDuration(driverEnd, driverStart))}; VLOG(DRIVER) << "BurstExecutorWithCache::execute timing = " << toString(timing); @@ -830,7 +857,7 @@ class BurstExecutorWithCache : public ExecutionBurstServer::IBurstExecutorWithCa } private: - const Model mModel; + const V1_3::Model mModel; const SampleDriver* const mDriver; const std::vector<RunTimePoolInfo> mModelPoolInfos; std::map<int32_t, std::optional<RunTimePoolInfo>> mMemoryCache; // cached requestPoolInfos @@ -852,7 +879,7 @@ static std::chrono::microseconds getPollingTimeWindow() { #endif // NN_DEBUGGABLE } -Return<void> SamplePreparedModel::configureExecutionBurst( +hardware::Return<void> SamplePreparedModel::configureExecutionBurst( const sp<V1_2::IBurstCallback>& callback, const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, @@ -860,7 +887,7 @@ Return<void> SamplePreparedModel::configureExecutionBurst( NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION, "SampleDriver::configureExecutionBurst"); - const bool preferPowerOverLatency = (kPreference == ExecutionPreference::LOW_POWER); + const bool preferPowerOverLatency = (kPreference == V1_1::ExecutionPreference::LOW_POWER); const auto pollingTimeWindow = (preferPowerOverLatency ? std::chrono::microseconds{0} : getPollingTimeWindow()); @@ -883,7 +910,7 @@ Return<void> SamplePreparedModel::configureExecutionBurst( cb(V1_0::ErrorStatus::NONE, burst); } - return Void(); + return hardware::Void(); } } // namespace sample_driver diff --git a/nn/driver/sample/SampleDriver.h b/nn/driver/sample/SampleDriver.h index 3628ee6c6..2482a9f4c 100644 --- a/nn/driver/sample/SampleDriver.h +++ b/nn/driver/sample/SampleDriver.h @@ -36,16 +36,17 @@ namespace sample_driver { using hardware::MQDescriptorSync; // Manages the data buffer for an operand. -class SampleBuffer : public hal::IBuffer { +class SampleBuffer : public V1_3::IBuffer { public: SampleBuffer(std::shared_ptr<ManagedBuffer> buffer, std::unique_ptr<BufferTracker::Token> token) : kBuffer(std::move(buffer)), kToken(std::move(token)) { CHECK(kBuffer != nullptr); CHECK(kToken != nullptr); } - hal::Return<hal::ErrorStatus> copyTo(const hal::hidl_memory& dst) override; - hal::Return<hal::ErrorStatus> copyFrom(const hal::hidl_memory& src, - const hal::hidl_vec<uint32_t>& dimensions) override; + hardware::Return<V1_3::ErrorStatus> copyTo(const hardware::hidl_memory& dst) override; + hardware::Return<V1_3::ErrorStatus> copyFrom( + const hardware::hidl_memory& src, + const hardware::hidl_vec<uint32_t>& dimensions) override; private: const std::shared_ptr<ManagedBuffer> kBuffer; @@ -57,7 +58,7 @@ class SampleBuffer : public hal::IBuffer { // // Since these drivers simulate hardware, they must run the computations // on the CPU. An actual driver would not do that. -class SampleDriver : public hal::IDevice { +class SampleDriver : public V1_3::IDevice { public: SampleDriver(const char* name, const IOperationResolver* operationResolver = BuiltinOperationResolver::get()) @@ -66,51 +67,50 @@ class SampleDriver : public hal::IDevice { mBufferTracker(BufferTracker::create()) { android::nn::initVLogMask(); } - hal::Return<void> getCapabilities(getCapabilities_cb cb) override; - hal::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb cb) override; - hal::Return<void> getCapabilities_1_2(getCapabilities_1_2_cb cb) override; - hal::Return<void> getVersionString(getVersionString_cb cb) override; - hal::Return<void> getType(getType_cb cb) override; - hal::Return<void> getSupportedExtensions(getSupportedExtensions_cb) override; - hal::Return<void> getSupportedOperations(const hal::V1_0::Model& model, - getSupportedOperations_cb cb) override; - hal::Return<void> getSupportedOperations_1_1(const hal::V1_1::Model& model, - getSupportedOperations_1_1_cb cb) override; - hal::Return<void> getSupportedOperations_1_2(const hal::V1_2::Model& model, - getSupportedOperations_1_2_cb cb) override; - hal::Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) override; - hal::Return<hal::V1_0::ErrorStatus> prepareModel( - const hal::V1_0::Model& model, - const sp<hal::V1_0::IPreparedModelCallback>& callback) override; - hal::Return<hal::V1_0::ErrorStatus> prepareModel_1_1( - const hal::V1_1::Model& model, hal::ExecutionPreference preference, - const sp<hal::V1_0::IPreparedModelCallback>& callback) override; - hal::Return<hal::V1_0::ErrorStatus> prepareModel_1_2( - const hal::V1_2::Model& model, hal::ExecutionPreference preference, - const hal::hidl_vec<hal::hidl_handle>& modelCache, - const hal::hidl_vec<hal::hidl_handle>& dataCache, const hal::CacheToken& token, - const sp<hal::V1_2::IPreparedModelCallback>& callback) override; - hal::Return<hal::V1_3::ErrorStatus> prepareModel_1_3( - const hal::V1_3::Model& model, hal::ExecutionPreference preference, - hal::Priority priority, const hal::OptionalTimePoint& deadline, - const hal::hidl_vec<hal::hidl_handle>& modelCache, - const hal::hidl_vec<hal::hidl_handle>& dataCache, const hal::CacheToken& token, - const sp<hal::V1_3::IPreparedModelCallback>& callback) override; - hal::Return<hal::V1_0::ErrorStatus> prepareModelFromCache( - const hal::hidl_vec<hal::hidl_handle>& modelCache, - const hal::hidl_vec<hal::hidl_handle>& dataCache, const hal::CacheToken& token, - const sp<hal::V1_2::IPreparedModelCallback>& callback) override; - hal::Return<hal::V1_3::ErrorStatus> prepareModelFromCache_1_3( - const hal::OptionalTimePoint& deadline, - const hal::hidl_vec<hal::hidl_handle>& modelCache, - const hal::hidl_vec<hal::hidl_handle>& dataCache, const hal::CacheToken& token, - const sp<hal::V1_3::IPreparedModelCallback>& callback) override; - hal::Return<hal::DeviceStatus> getStatus() override; - hal::Return<void> allocate(const hal::V1_3::BufferDesc& desc, - const hal::hidl_vec<sp<hal::V1_3::IPreparedModel>>& preparedModels, - const hal::hidl_vec<hal::V1_3::BufferRole>& inputRoles, - const hal::hidl_vec<hal::V1_3::BufferRole>& outputRoles, - allocate_cb cb) override; + hardware::Return<void> getCapabilities(getCapabilities_cb cb) override; + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb cb) override; + hardware::Return<void> getCapabilities_1_2(getCapabilities_1_2_cb cb) override; + hardware::Return<void> getVersionString(getVersionString_cb cb) override; + hardware::Return<void> getType(getType_cb cb) override; + hardware::Return<void> getSupportedExtensions(getSupportedExtensions_cb) override; + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb cb) override; + hardware::Return<void> getSupportedOperations_1_1(const V1_1::Model& model, + getSupportedOperations_1_1_cb cb) override; + hardware::Return<void> getSupportedOperations_1_2(const V1_2::Model& model, + getSupportedOperations_1_2_cb cb) override; + hardware::Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) override; + hardware::Return<V1_0::ErrorStatus> prepareModel( + const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback) override; + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, + const sp<V1_0::IPreparedModelCallback>& callback) override; + hardware::Return<V1_0::ErrorStatus> prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_2::IPreparedModelCallback>& callback) override; + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_3::IPreparedModelCallback>& callback) override; + hardware::Return<V1_0::ErrorStatus> prepareModelFromCache( + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_2::IPreparedModelCallback>& callback) override; + hardware::Return<V1_3::ErrorStatus> prepareModelFromCache_1_3( + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_3::IPreparedModelCallback>& callback) override; + hardware::Return<V1_0::DeviceStatus> getStatus() override; + hardware::Return<void> allocate( + const V1_3::BufferDesc& desc, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, + const hardware::hidl_vec<V1_3::BufferRole>& inputRoles, + const hardware::hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) override; // Starts and runs the driver service. Typically called from main(). // This will return only once the service shuts down. @@ -125,10 +125,10 @@ class SampleDriver : public hal::IDevice { const std::shared_ptr<BufferTracker> mBufferTracker; }; -class SamplePreparedModel : public hal::IPreparedModel { +class SamplePreparedModel : public V1_3::IPreparedModel { public: - SamplePreparedModel(const hal::Model& model, const SampleDriver* driver, - hal::ExecutionPreference preference, uid_t userId, hal::Priority priority) + SamplePreparedModel(const V1_3::Model& model, const SampleDriver* driver, + V1_1::ExecutionPreference preference, uid_t userId, V1_3::Priority priority) : mModel(model), mDriver(driver), kPreference(preference), @@ -138,64 +138,63 @@ class SamplePreparedModel : public hal::IPreparedModel { (void)kPriority; } bool initialize(); - hal::Return<hal::V1_0::ErrorStatus> execute( - const hal::V1_0::Request& request, - const sp<hal::V1_0::IExecutionCallback>& callback) override; - hal::Return<hal::V1_0::ErrorStatus> execute_1_2( - const hal::V1_0::Request& request, hal::MeasureTiming measure, - const sp<hal::V1_2::IExecutionCallback>& callback) override; - hal::Return<hal::V1_3::ErrorStatus> execute_1_3( - const hal::V1_3::Request& request, hal::MeasureTiming measure, - const hal::OptionalTimePoint& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration, - const sp<hal::V1_3::IExecutionCallback>& callback) override; - hal::Return<void> executeSynchronously(const hal::V1_0::Request& request, - hal::MeasureTiming measure, - executeSynchronously_cb cb) override; - hal::Return<void> executeSynchronously_1_3( - const hal::V1_3::Request& request, hal::MeasureTiming measure, - const hal::OptionalTimePoint& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration, + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) override; + hardware::Return<V1_0::ErrorStatus> execute_1_2( + const V1_0::Request& request, V1_2::MeasureTiming measure, + const sp<V1_2::IExecutionCallback>& callback) override; + hardware::Return<V1_3::ErrorStatus> execute_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const sp<V1_3::IExecutionCallback>& callback) override; + hardware::Return<void> executeSynchronously(const V1_0::Request& request, + V1_2::MeasureTiming measure, + executeSynchronously_cb cb) override; + hardware::Return<void> executeSynchronously_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb) override; - hal::Return<void> configureExecutionBurst( - const sp<hal::V1_2::IBurstCallback>& callback, - const MQDescriptorSync<hal::V1_2::FmqRequestDatum>& requestChannel, - const MQDescriptorSync<hal::V1_2::FmqResultDatum>& resultChannel, + hardware::Return<void> configureExecutionBurst( + const sp<V1_2::IBurstCallback>& callback, + const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, + const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, configureExecutionBurst_cb cb) override; - hal::Return<void> executeFenced(const hal::Request& request, - const hal::hidl_vec<hal::hidl_handle>& wait_for, - hal::MeasureTiming measure, - const hal::OptionalTimePoint& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& duration, - executeFenced_cb callback) override; - const hal::Model* getModel() const { return &mModel; } + hardware::Return<void> executeFenced(const V1_3::Request& request, + const hardware::hidl_vec<hardware::hidl_handle>& wait_for, + V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const V1_3::OptionalTimeoutDuration& duration, + executeFenced_cb callback) override; + const V1_3::Model* getModel() const { return &mModel; } protected: - hal::Model mModel; + V1_3::Model mModel; const SampleDriver* mDriver; std::vector<RunTimePoolInfo> mPoolInfos; - const hal::ExecutionPreference kPreference; + const V1_1::ExecutionPreference kPreference; const uid_t kUserId; - const hal::Priority kPriority; + const V1_3::Priority kPriority; }; -class SampleFencedExecutionCallback : public hal::IFencedExecutionCallback { +class SampleFencedExecutionCallback : public V1_3::IFencedExecutionCallback { public: - SampleFencedExecutionCallback(hal::Timing timingSinceLaunch, hal::Timing timingAfterFence, - hal::ErrorStatus error) + SampleFencedExecutionCallback(V1_2::Timing timingSinceLaunch, V1_2::Timing timingAfterFence, + V1_3::ErrorStatus error) : kTimingSinceLaunch(timingSinceLaunch), kTimingAfterFence(timingAfterFence), kErrorStatus(error) {} - hal::Return<void> getExecutionInfo(getExecutionInfo_cb callback) override { + hardware::Return<void> getExecutionInfo(getExecutionInfo_cb callback) override { callback(kErrorStatus, kTimingSinceLaunch, kTimingAfterFence); - return hal::Void(); + return hardware::Void(); } private: - const hal::Timing kTimingSinceLaunch; - const hal::Timing kTimingAfterFence; - const hal::ErrorStatus kErrorStatus; + const V1_2::Timing kTimingSinceLaunch; + const V1_2::Timing kTimingAfterFence; + const V1_3::ErrorStatus kErrorStatus; }; } // namespace sample_driver diff --git a/nn/driver/sample/SampleDriverFloatFast.cpp b/nn/driver/sample/SampleDriverFloatFast.cpp index 5d2cd1344..0ee467025 100644 --- a/nn/driver/sample/SampleDriverFloatFast.cpp +++ b/nn/driver/sample/SampleDriverFloatFast.cpp @@ -31,34 +31,32 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - class SampleDriverFloatFast : public SampleDriverPartial { public: SampleDriverFloatFast() : SampleDriverPartial("nnapi-sample_float_fast") {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; private: std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const override; }; -Return<void> SampleDriverFloatFast::getCapabilities_1_3(getCapabilities_1_3_cb cb) { +hardware::Return<void> SampleDriverFloatFast::getCapabilities_1_3(getCapabilities_1_3_cb cb) { android::nn::initVLogMask(); VLOG(DRIVER) << "getCapabilities()"; - Capabilities capabilities = { + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = {.execTime = 0.7f, .powerUsage = 1.1f}, .relaxedFloat32toFloat16PerformanceTensor = {.execTime = 0.7f, .powerUsage = 1.1f}, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>({1.0f, 1.0f}), .ifPerformance = {.execTime = 1.0f, .powerUsage = 1.0f}, .whilePerformance = {.execTime = 1.0f, .powerUsage = 1.0f}}; - update(&capabilities.operandPerformance, OperandType::TENSOR_FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32, {.execTime = 0.8f, .powerUsage = 1.2f}); - update(&capabilities.operandPerformance, OperandType::FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::FLOAT32, {.execTime = 0.8f, .powerUsage = 1.2f}); - cb(ErrorStatus::NONE, capabilities); - return Void(); + cb(V1_3::ErrorStatus::NONE, capabilities); + return hardware::Void(); } std::vector<bool> SampleDriverFloatFast::getSupportedOperationsImpl( @@ -66,10 +64,10 @@ std::vector<bool> SampleDriverFloatFast::getSupportedOperationsImpl( const size_t count = model.main.operations.size(); std::vector<bool> supported(count); for (size_t i = 0; i < count; i++) { - const Operation& operation = model.main.operations[i]; + const V1_3::Operation& operation = model.main.operations[i]; if (!isExtensionOperationType(operation.type) && operation.inputs.size() > 0) { - const Operand& firstOperand = model.main.operands[operation.inputs[0]]; - supported[i] = firstOperand.type == OperandType::TENSOR_FLOAT32; + const V1_3::Operand& firstOperand = model.main.operands[operation.inputs[0]]; + supported[i] = firstOperand.type == V1_3::OperandType::TENSOR_FLOAT32; } } return supported; diff --git a/nn/driver/sample/SampleDriverFloatSlow.cpp b/nn/driver/sample/SampleDriverFloatSlow.cpp index 1e6f0cb0d..009cd5af6 100644 --- a/nn/driver/sample/SampleDriverFloatSlow.cpp +++ b/nn/driver/sample/SampleDriverFloatSlow.cpp @@ -31,34 +31,32 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - class SampleDriverFloatSlow : public SampleDriverPartial { public: SampleDriverFloatSlow() : SampleDriverPartial("nnapi-sample_float_slow") {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; private: std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const override; }; -Return<void> SampleDriverFloatSlow::getCapabilities_1_3(getCapabilities_1_3_cb cb) { +hardware::Return<void> SampleDriverFloatSlow::getCapabilities_1_3(getCapabilities_1_3_cb cb) { android::nn::initVLogMask(); VLOG(DRIVER) << "getCapabilities()"; - Capabilities capabilities = { + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = {.execTime = 1.2f, .powerUsage = 0.6f}, .relaxedFloat32toFloat16PerformanceTensor = {.execTime = 1.2f, .powerUsage = 0.6f}, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>({1.0f, 1.0f}), .ifPerformance = {.execTime = 1.0f, .powerUsage = 1.0f}, .whilePerformance = {.execTime = 1.0f, .powerUsage = 1.0f}}; - update(&capabilities.operandPerformance, OperandType::TENSOR_FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32, {.execTime = 1.3f, .powerUsage = 0.7f}); - update(&capabilities.operandPerformance, OperandType::FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::FLOAT32, {.execTime = 1.3f, .powerUsage = 0.7f}); - cb(ErrorStatus::NONE, capabilities); - return Void(); + cb(V1_3::ErrorStatus::NONE, capabilities); + return hardware::Void(); } std::vector<bool> SampleDriverFloatSlow::getSupportedOperationsImpl( @@ -66,10 +64,10 @@ std::vector<bool> SampleDriverFloatSlow::getSupportedOperationsImpl( const size_t count = model.main.operations.size(); std::vector<bool> supported(count); for (size_t i = 0; i < count; i++) { - const Operation& operation = model.main.operations[i]; + const V1_3::Operation& operation = model.main.operations[i]; if (!isExtensionOperationType(operation.type) && operation.inputs.size() > 0) { - const Operand& firstOperand = model.main.operands[operation.inputs[0]]; - supported[i] = firstOperand.type == OperandType::TENSOR_FLOAT32; + const V1_3::Operand& firstOperand = model.main.operands[operation.inputs[0]]; + supported[i] = firstOperand.type == V1_3::OperandType::TENSOR_FLOAT32; } } return supported; diff --git a/nn/driver/sample/SampleDriverFloatXNNPACK.cpp b/nn/driver/sample/SampleDriverFloatXNNPACK.cpp index 3a8c0a2df..db24b59c0 100644 --- a/nn/driver/sample/SampleDriverFloatXNNPACK.cpp +++ b/nn/driver/sample/SampleDriverFloatXNNPACK.cpp @@ -43,20 +43,18 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - namespace { -#define NN_DRIVER_RETURN_IF_ERROR(expr) \ - do { \ - ErrorStatus _errorCode = (expr); \ - if (_errorCode != ErrorStatus::NONE) { \ - return _errorCode; \ - } \ +#define NN_DRIVER_RETURN_IF_ERROR(expr) \ + do { \ + V1_3::ErrorStatus _errorCode = (expr); \ + if (_errorCode != V1_3::ErrorStatus::NONE) { \ + return _errorCode; \ + } \ } while (0) const size_t kNumOfWorkerThreads = 1; -static const Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; +static const V1_2::Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; bool isScalarType(OperandType type) { switch (type) { @@ -72,13 +70,13 @@ bool isScalarType(OperandType type) { } void updateForArguments(const std::vector<uint32_t>& indexes, - const hidl_vec<RequestArgument>& arguments, + const hardware::hidl_vec<V1_0::RequestArgument>& arguments, const std::vector<RunTimePoolInfo>& requestPoolInfos, RunTimeOperandInfo* operands) { CHECK_EQ(indexes.size(), arguments.size()); for (size_t i = 0; i < indexes.size(); i++) { const uint32_t operandIndex = indexes[i]; - const RequestArgument& from = arguments[i]; + const V1_0::RequestArgument& from = arguments[i]; RunTimeOperandInfo& to = operands[operandIndex]; if (from.dimensions.size() > 0) { // It's the responsibility of the caller to validate that @@ -89,7 +87,7 @@ void updateForArguments(const std::vector<uint32_t>& indexes, to.dimensions = from.dimensions; } if (from.hasNoValue) { - to.lifetime = OperandLifeTime::NO_VALUE; + to.lifetime = Operand::LifeTime::NO_VALUE; CHECK(to.buffer == nullptr); to.length = 0; } else { @@ -108,30 +106,30 @@ void updateForArguments(const std::vector<uint32_t>& indexes, } std::vector<RunTimeOperandInfo> initializeRunTimeInfo( - const Subgraph& subgraph, const std::vector<RunTimePoolInfo>& modelPoolInfos, - const hidl_vec<uint8_t>* mModelOperandValues) { + const V1_3::Subgraph& subgraph, const std::vector<RunTimePoolInfo>& modelPoolInfos, + const hardware::hidl_vec<uint8_t>* mModelOperandValues) { const size_t count = subgraph.operands.size(); std::vector<RunTimeOperandInfo> operands(count); for (size_t i = 0; i < count; i++) { - const Operand& from = subgraph.operands[i]; + const V1_3::Operand& from = subgraph.operands[i]; RunTimeOperandInfo& to = operands[i]; - to.type = from.type; + to.type = uncheckedConvert(from.type); to.dimensions = from.dimensions; to.scale = from.scale; to.zeroPoint = from.zeroPoint; to.length = from.location.length; - to.lifetime = from.lifetime; - to.extraParams = from.extraParams; + to.lifetime = uncheckedConvert(from.lifetime); + to.extraParams = uncheckedConvert(from.extraParams); switch (from.lifetime) { - case OperandLifeTime::TEMPORARY_VARIABLE: + case V1_3::OperandLifeTime::TEMPORARY_VARIABLE: to.buffer = nullptr; to.numberOfUsesLeft = from.numberOfConsumers; break; - case OperandLifeTime::CONSTANT_COPY: + case V1_3::OperandLifeTime::CONSTANT_COPY: to.buffer = const_cast<uint8_t*>(&(*mModelOperandValues)[from.location.offset]); to.numberOfUsesLeft = 0; break; - case OperandLifeTime::CONSTANT_REFERENCE: { + case V1_3::OperandLifeTime::CONSTANT_REFERENCE: { auto poolIndex = from.location.poolIndex; CHECK_LT(poolIndex, modelPoolInfos.size()); auto& r = modelPoolInfos[poolIndex]; @@ -139,10 +137,10 @@ std::vector<RunTimeOperandInfo> initializeRunTimeInfo( to.numberOfUsesLeft = 0; break; } - case OperandLifeTime::SUBGRAPH: - case OperandLifeTime::SUBGRAPH_INPUT: - case OperandLifeTime::SUBGRAPH_OUTPUT: - case OperandLifeTime::NO_VALUE: + case V1_3::OperandLifeTime::SUBGRAPH: + case V1_3::OperandLifeTime::SUBGRAPH_INPUT: + case V1_3::OperandLifeTime::SUBGRAPH_OUTPUT: + case V1_3::OperandLifeTime::NO_VALUE: to.buffer = nullptr; to.numberOfUsesLeft = 0; break; @@ -155,7 +153,7 @@ std::vector<RunTimeOperandInfo> initializeRunTimeInfo( class Subgraph { public: - static Subgraph* Create(const hidl_vec<Operation>& operations, + static Subgraph* Create(const hardware::hidl_vec<V1_3::Operation>& operations, std::vector<RunTimeOperandInfo>& operands, const std::vector<uint32_t>& inputIndexes, const std::vector<uint32_t>& outputIndexes, pthreadpool_t threadpool, @@ -182,13 +180,13 @@ class Subgraph { std::vector<int> tensors(operands.size(), -1); for (const auto& operation : operations) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + const std::vector<uint32_t>& ins = operation.inputs; + const std::vector<uint32_t>& outs = operation.outputs; switch (operation.type) { - case OperationType::MEAN: - case OperationType::PAD: - case OperationType::RESHAPE: - case OperationType::RESIZE_BILINEAR: + case V1_3::OperationType::MEAN: + case V1_3::OperationType::PAD: + case V1_3::OperationType::RESHAPE: + case V1_3::OperationType::RESIZE_BILINEAR: // Ignore the second input (axes, static padding, or new shape), // because it is represented as parameters of the XNNPACK operator // rather than extra input. @@ -223,8 +221,9 @@ class Subgraph { uint32_t flags = 0; const void* data = nullptr; - if (operands[tensors[t]].lifetime == OperandLifeTime::CONSTANT_COPY || - operands[tensors[t]].lifetime == OperandLifeTime::CONSTANT_REFERENCE) { + if (operands[tensors[t]].lifetime == Operand::LifeTime::CONSTANT_COPY || + operands[tensors[t]].lifetime == Operand::LifeTime::CONSTANT_REFERENCE || + operands[tensors[t]].lifetime == Operand::LifeTime::POINTER) { data = operands[tensors[t]].buffer; } if (inputs.count(t) != 0) { @@ -254,7 +253,7 @@ class Subgraph { // Create XNNPACK nodes for NNAPI Operations for (const auto& operation : operations) { if (VisitNode(subgraph.get(), operation, operands.data(), xnnpackTensors) != - ErrorStatus::NONE) { + V1_3::ErrorStatus::NONE) { LOG(ERROR) << "XNNPACK add op failed"; return nullptr; } @@ -269,9 +268,9 @@ class Subgraph { return new Subgraph(runtimePtr, std::move(externals), useStaticBuffer); } - ErrorStatus Prepare() { return ErrorStatus::NONE; } + V1_3::ErrorStatus Prepare() { return V1_3::ErrorStatus::NONE; } - ErrorStatus Invoke(RunTimeOperandInfo* operands) { + V1_3::ErrorStatus Invoke(RunTimeOperandInfo* operands) { VLOG(DRIVER) << "Subgraph::Invoke() start"; if (!mUseStaticBuffer || mFirstRun) { VLOG(DRIVER) << "Setup buffer for Subgraph"; @@ -288,7 +287,7 @@ class Subgraph { xnn_setup_runtime(mRuntime.get(), externalValues.size(), externalValues.data()); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_setup_runtime FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } mFirstRun = false; } @@ -296,273 +295,273 @@ class Subgraph { const xnn_status status = xnn_invoke_runtime(mRuntime.get()); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_invoke_runtime FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CalculatePadding(int padding, uint32_t* flags) { + static V1_3::ErrorStatus CalculatePadding(int padding, uint32_t* flags) { switch (padding) { case ANEURALNETWORKS_PADDING_SAME: *flags = XNN_FLAG_TENSORFLOW_SAME_PADDING; - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; case ANEURALNETWORKS_PADDING_VALID: *flags = 0; - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; default: LOG(ERROR) << "invalid padding mode"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } - static ErrorStatus ConvertActivationToOutputRange(int activation, float* outputMin, - float* outputMax) { + static V1_3::ErrorStatus ConvertActivationToOutputRange(int activation, float* outputMin, + float* outputMax) { switch (activation) { case ANEURALNETWORKS_FUSED_NONE: *outputMin = -std::numeric_limits<float>::infinity(); *outputMax = +std::numeric_limits<float>::infinity(); - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; case ANEURALNETWORKS_FUSED_RELU: *outputMin = 0.0f; *outputMax = +std::numeric_limits<float>::infinity(); - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; case ANEURALNETWORKS_FUSED_RELU1: *outputMin = -1.0f; *outputMax = +1.0f; - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; case ANEURALNETWORKS_FUSED_RELU6: *outputMin = 0.0f; *outputMax = 6.0f; - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; default: - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } - static ErrorStatus CheckConvolutionParams(int32_t stride_width, int32_t stride_height, - int32_t dilation_width_factor, - int32_t dilation_height_factor) { + static V1_3::ErrorStatus CheckConvolutionParams(int32_t stride_width, int32_t stride_height, + int32_t dilation_width_factor, + int32_t dilation_height_factor) { if (stride_width <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (stride_height <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (dilation_width_factor <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (dilation_height_factor <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckDepthwiseConvolutionParams(int32_t stride_width, int32_t stride_height, - int32_t dilation_width_factor, - int32_t dilation_height_factor, - int32_t depth_multiplier, - uint32_t output_channels) { + static V1_3::ErrorStatus CheckDepthwiseConvolutionParams( + int32_t stride_width, int32_t stride_height, int32_t dilation_width_factor, + int32_t dilation_height_factor, int32_t depth_multiplier, uint32_t output_channels) { if (stride_width <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (stride_height <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (depth_multiplier <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (output_channels % depth_multiplier != 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (dilation_width_factor <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (dilation_height_factor <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckPoolingParams(int32_t stride_width, int32_t stride_height, - int32_t filter_width, int32_t filter_height) { + static V1_3::ErrorStatus CheckPoolingParams(int32_t stride_width, int32_t stride_height, + int32_t filter_width, int32_t filter_height) { if (stride_width <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (stride_height <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (filter_width <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (filter_height <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (filter_width == 1 && filter_height == 1 && std::max(stride_width, stride_height) > 1) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckNumInputsAndOutputs(const Operation& operation, - uint32_t expected_num_inputs, - uint32_t expected_num_outputs) { + static V1_3::ErrorStatus CheckNumInputsAndOutputs(const V1_3::Operation& operation, + uint32_t expected_num_inputs, + uint32_t expected_num_outputs) { if (operation.inputs.size() != expected_num_inputs) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (operation.outputs.size() != expected_num_outputs) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckTensorType(OperandType tensor_type, OperandType expected_type) { + static V1_3::ErrorStatus CheckTensorType(OperandType tensor_type, OperandType expected_type) { if (tensor_type != expected_type) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckTensorFloatType(OperandType tensor_type) { + static V1_3::ErrorStatus CheckTensorFloatType(OperandType tensor_type) { if (tensor_type != OperandType::TENSOR_FLOAT32) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckTensorShape(std::vector<uint32_t>& dimensions, uint32_t min_num_dims, - uint32_t max_num_dims) { + static V1_3::ErrorStatus CheckTensorShape(std::vector<uint32_t>& dimensions, + uint32_t min_num_dims, uint32_t max_num_dims) { if (min_num_dims == max_num_dims) { if (dimensions.size() != min_num_dims) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } else { if (dimensions.size() < min_num_dims || dimensions.size() > max_num_dims) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } for (size_t i = 0; i < dimensions.size(); i++) { if (dimensions[i] <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckTensorShape(std::vector<uint32_t>& dimensions, int expected_num_dims) { + static V1_3::ErrorStatus CheckTensorShape(std::vector<uint32_t>& dimensions, + int expected_num_dims) { return CheckTensorShape(dimensions, expected_num_dims, expected_num_dims); } - static ErrorStatus CheckSlopeTensorShape(std::vector<uint32_t>& dimensions) { + static V1_3::ErrorStatus CheckSlopeTensorShape(std::vector<uint32_t>& dimensions) { if (dimensions.size() < 1) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } // Validate that all non-channel dimensions (if any) are exactly 1. for (size_t i = 0; i < dimensions.size() - 1; i++) { if (dimensions[i] != 1) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckAxesTensorShape(std::vector<uint32_t>& dimensions) { + static V1_3::ErrorStatus CheckAxesTensorShape(std::vector<uint32_t>& dimensions) { if (dimensions.size() != 1) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckShapeTensorShape(std::vector<uint32_t>& dimensions) { + static V1_3::ErrorStatus CheckShapeTensorShape(std::vector<uint32_t>& dimensions) { if (dimensions.size() != 1) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus CheckTensorStaticAllocation(OperandLifeTime lifetime) { - if (lifetime != OperandLifeTime::CONSTANT_COPY && - lifetime != OperandLifeTime::CONSTANT_REFERENCE) { - VLOG(DRIVER) << "CheckTensorStaticAllocation: " << toString(lifetime); - return ErrorStatus::INVALID_ARGUMENT; + static V1_3::ErrorStatus CheckTensorStaticAllocation(Operand::LifeTime lifetime) { + if (lifetime != Operand::LifeTime::CONSTANT_COPY && + lifetime != Operand::LifeTime::CONSTANT_REFERENCE && + lifetime != Operand::LifeTime::POINTER) { + VLOG(DRIVER) << "CheckTensorStaticAllocation: " << toString(convertToV1_3(lifetime)); + return V1_3::ErrorStatus::INVALID_ARGUMENT; } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { + static V1_3::ErrorStatus VisitNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { switch (operation.type) { - case OperationType::ABS: + case V1_3::OperationType::ABS: return VisitAbsNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::ADD: + case V1_3::OperationType::ADD: return VisitAddNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::AVERAGE_POOL_2D: + case V1_3::OperationType::AVERAGE_POOL_2D: return VisitAveragePool2DNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::CONV_2D: + case V1_3::OperationType::CONV_2D: return VisitConv2DNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::DEPTHWISE_CONV_2D: + case V1_3::OperationType::DEPTHWISE_CONV_2D: return VisitDepthwiseConv2DNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::DIV: + case V1_3::OperationType::DIV: return VisitDivNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::FLOOR: + case V1_3::OperationType::FLOOR: return VisitFloorNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::FULLY_CONNECTED: + case V1_3::OperationType::FULLY_CONNECTED: return VisitFullyConnectedNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::HARD_SWISH: + case V1_3::OperationType::HARD_SWISH: return VisitHardSwishNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::LOGISTIC: + case V1_3::OperationType::LOGISTIC: return VisitLogisticNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::MAX_POOL_2D: + case V1_3::OperationType::MAX_POOL_2D: return VisitMaxPool2DNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::MAXIMUM: + case V1_3::OperationType::MAXIMUM: return VisitMaximumNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::MEAN: + case V1_3::OperationType::MEAN: return VisitMeanNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::MINIMUM: + case V1_3::OperationType::MINIMUM: return VisitMinimumNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::MUL: + case V1_3::OperationType::MUL: return VisitMulNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::NEG: + case V1_3::OperationType::NEG: return VisitNegNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::PAD: + case V1_3::OperationType::PAD: return VisitPadNode(subgraph, operation, operands, 0.0f, xnnpackTensors); - case OperationType::PAD_V2: + case V1_3::OperationType::PAD_V2: return VisitPadV2Node(subgraph, operation, operands, xnnpackTensors); - case OperationType::RESHAPE: + case V1_3::OperationType::RESHAPE: return VisitReshapeNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::RESIZE_BILINEAR: + case V1_3::OperationType::RESIZE_BILINEAR: return VisitResizeBilinearNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::PRELU: + case V1_3::OperationType::PRELU: return VisitPreluNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::RELU: + case V1_3::OperationType::RELU: return VisitReluNode(subgraph, operation, operands, 0.0f, std::numeric_limits<float>::infinity(), xnnpackTensors); - case OperationType::RELU1: + case V1_3::OperationType::RELU1: return VisitReluNode(subgraph, operation, operands, -1.0f, 1.0f, xnnpackTensors); - case OperationType::RELU6: + case V1_3::OperationType::RELU6: return VisitReluNode(subgraph, operation, operands, 0.0f, 6.0f, xnnpackTensors); - case OperationType::SQRT: + case V1_3::OperationType::SQRT: return VisitSqrtNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::SUB: + case V1_3::OperationType::SUB: return VisitSubNode(subgraph, operation, operands, xnnpackTensors); - case OperationType::SOFTMAX: + case V1_3::OperationType::SOFTMAX: return VisitSoftmaxNode(subgraph, operation, operands, xnnpackTensors); default: - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } - static ErrorStatus VisitAbsNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitAbsNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -572,17 +571,17 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_abs FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitAddNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitAddNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[2]].lifetime)); @@ -602,17 +601,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_add2 FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitAveragePool2DNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitAveragePool2DNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); // Make sure all scalar params are constant. @@ -629,7 +629,7 @@ class Subgraph { } if (use_nchw) { VLOG(DRIVER) << "XNNPACK VisitAveragePool2DNode FAILED: only NHWC layout is supported"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } int32_t stride_width, stride_height, filter_width, filter_height, activation; @@ -684,17 +684,18 @@ class Subgraph { } if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_average_pooling_2d FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitConv2DNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitConv2DNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[1]].lifetime)); @@ -715,7 +716,7 @@ class Subgraph { } if (use_nchw) { VLOG(DRIVER) << "XNNPACK VisitConv2DNode FAILED: only NHWC layout is supported"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } int32_t stride_width, stride_height, activation; @@ -781,18 +782,19 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], flags); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_convolution_2d FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitDepthwiseConv2DNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitDepthwiseConv2DNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[1]].lifetime)); @@ -814,7 +816,7 @@ class Subgraph { if (use_nchw) { VLOG(DRIVER) << "XNNPACK VisitDepthwiseConv2DNode FAILED: only NHWC layout is supported"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } int32_t stride_width, stride_height, depth_multiplier, activation; @@ -882,17 +884,17 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], flags); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_depthwise_convolution_2d FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitDivNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitDivNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[2]].lifetime)); @@ -912,17 +914,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_divide FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitFullyConnectedNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitFullyConnectedNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[1]].lifetime)); @@ -947,17 +950,18 @@ class Subgraph { /*flags=*/XNN_FLAG_TENSORFLOW_RESHAPE_2D); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_fully_connected FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitFloorNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitFloorNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -968,17 +972,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_floor FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitHardSwishNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitHardSwishNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -988,17 +993,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_hardswish FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitLogisticNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitLogisticNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -1008,17 +1014,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_sigmoid FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitMaxPool2DNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitMaxPool2DNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); // Make sure all scalar params are constant. @@ -1035,7 +1042,7 @@ class Subgraph { } if (use_nchw) { VLOG(DRIVER) << "XNNPACK VisitMaxPool2DNode FAILED: only NHWC layout is supported"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } int32_t stride_width, stride_height, filter_width, filter_height, activation; @@ -1091,17 +1098,18 @@ class Subgraph { } if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_max_pooling_2d FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitMaximumNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitMaximumNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[2]].lifetime)); @@ -1121,17 +1129,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_maximum2 FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitMeanNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitMeanNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorShape(operands[ins[0]].dimensions, 4)); NN_DRIVER_RETURN_IF_ERROR(CheckAxesTensorShape(operands[ins[1]].dimensions)); @@ -1143,17 +1152,17 @@ class Subgraph { int keep_dims = getScalarData<int32_t>(operands[ins[2]]); if (keep_dims <= 0) { LOG(ERROR) << "XNNPACK VisitMeanNode FAILED: only support keep_dims"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } const int32_t* axes_buffer = reinterpret_cast<const int32_t*>(operands[ins[1]].buffer); if (operands[ins[1]].dimensions[0] != 2) { LOG(ERROR) << "XNNPACK VisitMeanNode FAILED: unsupported axes"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (std::min(axes_buffer[0], axes_buffer[1]) != 1 || std::max(axes_buffer[0], axes_buffer[1]) != 2) { LOG(ERROR) << "XNNPACK VisitMeanNode FAILED: unsupported axes"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (subgraph != nullptr) { const xnn_status status = xnn_define_global_average_pooling_2d( @@ -1164,17 +1173,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_global_average_pooling_2d FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitMinimumNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitMinimumNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[2]].lifetime)); @@ -1194,17 +1204,17 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_minimum2 FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitMulNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitMulNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[2]].lifetime)); @@ -1224,17 +1234,17 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_multiply2 FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitNegNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitNegNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -1245,17 +1255,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_negate FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitPreluNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitPreluNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR( CheckTensorShape(operands[ins[0]].dimensions, 1, XNN_MAX_TENSOR_DIMS)); @@ -1272,17 +1283,17 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_prelu FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitPadNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, float padding_value, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitPadNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, float padding_value, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR( CheckTensorShape(operands[ins[0]].dimensions, 1, XNN_MAX_TENSOR_DIMS)); @@ -1293,7 +1304,7 @@ class Subgraph { const int32_t* paddings_data = reinterpret_cast<const int32_t*>(operands[ins[1]].buffer); for (size_t i = 0; i < operands[ins[1]].dimensions.size() * 2; i++) { - if (paddings_data[i] < 0) return ErrorStatus::INVALID_ARGUMENT; + if (paddings_data[i] < 0) return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (subgraph != nullptr) { std::array<size_t, XNN_MAX_TENSOR_DIMS> pre_paddings{}; @@ -1308,28 +1319,30 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_static_constant_pad FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitPadV2Node(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; + static V1_3::ErrorStatus VisitPadV2Node(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; if (operands[ins[2]].type != OperandType::FLOAT32) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } float padding_value = getScalarData<float>(operands[ins[2]]); return VisitPadNode(subgraph, operation, operands, padding_value, xnnpackTensors); } - static ErrorStatus VisitReshapeNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitReshapeNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR( CheckTensorShape(operands[ins[0]].dimensions, 0, XNN_MAX_TENSOR_DIMS)); @@ -1350,17 +1363,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_static_reshape FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitResizeBilinearNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitResizeBilinearNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorShape(operands[ins[0]].dimensions, 4)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -1375,7 +1389,7 @@ class Subgraph { if (use_nchw) { VLOG(DRIVER) << "XNNPACK VisitResizeBilinearNode FAILED: only NHWC layout is supported"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } @@ -1389,12 +1403,12 @@ class Subgraph { float width_scale = getScalarData<float>(operands[ins[1]]); float height_scale = getScalarData<float>(operands[ins[2]]); if (width_scale <= 0 || height_scale <= 0) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } new_height = static_cast<size_t>(operands[ins[0]].dimensions[1] * height_scale); new_width = static_cast<size_t>(operands[ins[0]].dimensions[2] * width_scale); } else { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } bool align_corners = false; @@ -1404,7 +1418,7 @@ class Subgraph { half_pixel_centers = getScalarData<bool>(operands[ins[5]]); } if (align_corners && !half_pixel_centers) { - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (subgraph != nullptr) { uint32_t flags = 0; @@ -1419,17 +1433,19 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], flags); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_static_resize_bilinear_2d FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitReluNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, float outputMin, float outputMax, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitReluNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, float outputMin, + float outputMax, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -1440,17 +1456,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_clamp FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitSqrtNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitSqrtNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -1461,17 +1478,17 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_bankers_rounding FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitSubNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitSubNode(xnn_subgraph_t subgraph, const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[1]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[2]].lifetime)); @@ -1491,17 +1508,18 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_subtract FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } - static ErrorStatus VisitSoftmaxNode(xnn_subgraph_t subgraph, const Operation& operation, - RunTimeOperandInfo* operands, - const std::vector<uint32_t>& xnnpackTensors) { - const hidl_vec<uint32_t>& ins = operation.inputs; - const hidl_vec<uint32_t>& outs = operation.outputs; + static V1_3::ErrorStatus VisitSoftmaxNode(xnn_subgraph_t subgraph, + const V1_3::Operation& operation, + RunTimeOperandInfo* operands, + const std::vector<uint32_t>& xnnpackTensors) { + const hardware::hidl_vec<uint32_t>& ins = operation.inputs; + const hardware::hidl_vec<uint32_t>& outs = operation.outputs; NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[ins[0]].type)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[1]].lifetime)); NN_DRIVER_RETURN_IF_ERROR(CheckTensorFloatType(operands[outs[0]].type)); @@ -1509,14 +1527,14 @@ class Subgraph { float beta = getScalarData<float>(operands[ins[1]]); if (beta != 1.0f) { LOG(ERROR) << "XNNPACK VisitSoftmaxNode FAILED, unsupported beta value: " << beta; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (ins.size() >= 3) { NN_DRIVER_RETURN_IF_ERROR(CheckTensorStaticAllocation(operands[ins[2]].lifetime)); int axis = getScalarData<int32_t>(operands[ins[2]]); if (axis != -1) { LOG(ERROR) << "XNNPACK VisitSoftmaxNode FAILED, unsupported axis value: " << axis; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } } if (subgraph != nullptr) { @@ -1525,11 +1543,11 @@ class Subgraph { /*output_id=*/xnnpackTensors[outs[0]], /*flags=*/0); if (status != xnn_status_success) { LOG(ERROR) << "XNNPACK xnn_define_softmax FAILED"; - return ErrorStatus::GENERAL_FAILURE; + return V1_3::ErrorStatus::GENERAL_FAILURE; } } - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } private: @@ -1550,8 +1568,9 @@ class Subgraph { class SamplePreparedModelXNNPACK : public SamplePreparedModel { public: - SamplePreparedModelXNNPACK(const Model& model, const SampleDriver* driver, - ExecutionPreference preference, uid_t userId, Priority priority) + SamplePreparedModelXNNPACK(const V1_3::Model& model, const SampleDriver* driver, + V1_1::ExecutionPreference preference, uid_t userId, + V1_3::Priority priority) : SamplePreparedModel(model, driver, preference, userId, priority), mSubgraph(nullptr), mThreadpool(nullptr) {} @@ -1560,30 +1579,36 @@ class SamplePreparedModelXNNPACK : public SamplePreparedModel { pthreadpool_destroy(mThreadpool); }; bool initialize(); - Return<V1_0::ErrorStatus> execute(const V1_0::Request& request, - const sp<V1_0::IExecutionCallback>& callback) override; - Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request& request, MeasureTiming measure, - const sp<V1_2::IExecutionCallback>& callback) override; - Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request& request, MeasureTiming measure, - const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const sp<V1_3::IExecutionCallback>& callback) override; - Return<void> executeSynchronously(const V1_0::Request& request, MeasureTiming measure, - executeSynchronously_cb cb) override; - Return<void> executeSynchronously_1_3(const Request& request, MeasureTiming measure, - const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - executeSynchronously_1_3_cb cb) override; - Return<void> configureExecutionBurst( + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) override; + hardware::Return<V1_0::ErrorStatus> execute_1_2( + const V1_0::Request& request, V1_2::MeasureTiming measure, + const sp<V1_2::IExecutionCallback>& callback) override; + hardware::Return<V1_3::ErrorStatus> execute_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const sp<V1_3::IExecutionCallback>& callback) override; + hardware::Return<void> executeSynchronously(const V1_0::Request& request, + V1_2::MeasureTiming measure, + executeSynchronously_cb cb) override; + hardware::Return<void> executeSynchronously_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + executeSynchronously_1_3_cb cb) override; + hardware::Return<void> configureExecutionBurst( const sp<V1_2::IBurstCallback>& callback, const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, configureExecutionBurst_cb cb) override; - Return<void> executeFenced(const Request& request, const hidl_vec<hidl_handle>& wait_for, - MeasureTiming measure, const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const OptionalTimeoutDuration& duration, - executeFenced_cb callback) override; + hardware::Return<void> executeFenced(const V1_3::Request& request, + const hardware::hidl_vec<hardware::hidl_handle>& wait_for, + V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const V1_3::OptionalTimeoutDuration& duration, + executeFenced_cb callback) override; private: Subgraph* mSubgraph; @@ -1591,14 +1616,14 @@ class SamplePreparedModelXNNPACK : public SamplePreparedModel { pthreadpool* mThreadpool; }; -Return<void> SamplePreparedModelXNNPACK::configureExecutionBurst( +hardware::Return<void> SamplePreparedModelXNNPACK::configureExecutionBurst( const sp<V1_2::IBurstCallback>& callback, const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, configureExecutionBurst_cb cb) { VLOG(DRIVER) << "SamplePreparedModelXNNPACK::configureExecutionBurst not supported"; cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); - return Void(); + return hardware::Void(); } bool SamplePreparedModelXNNPACK::initialize() { @@ -1608,7 +1633,7 @@ bool SamplePreparedModelXNNPACK::initialize() { VLOG(DRIVER) << "SamplePreparedModelXNNPACK::initialize failed to create pthreadpool, " "fallback to single threaded execution"; } - const Model* model = getModel(); + const V1_3::Model* model = getModel(); mOperands = initializeRunTimeInfo(model->main, mPoolInfos, &model->operandValues); mSubgraph = Subgraph::Create(model->main.operations, mOperands, model->main.inputIndexes, model->main.outputIndexes, mThreadpool); @@ -1616,20 +1641,20 @@ bool SamplePreparedModelXNNPACK::initialize() { } template <typename T_IExecutionCallback> -void asyncExecuteXNNPACK(Subgraph* subgraph, RunTimeOperandInfo* operands, const Request& request, - MeasureTiming measure, const Model& model, - const std::optional<Deadline>& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, +void asyncExecuteXNNPACK(Subgraph* subgraph, RunTimeOperandInfo* operands, + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::Model& model, const std::optional<Deadline>& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, const sp<T_IExecutionCallback>& callback) { std::vector<RunTimePoolInfo> requestPoolInfos; - if (!setRunTimePoolInfosFromMemoryPools(&requestPoolInfos, request.pools)) { - notify(callback, ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + if (!setRunTimePoolInfosFromMemoryPools(&requestPoolInfos, uncheckedConvert(request.pools))) { + notify(callback, V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); } updateForArguments(model.main.inputIndexes, request.inputs, requestPoolInfos, operands); updateForArguments(model.main.outputIndexes, request.outputs, requestPoolInfos, operands); auto status = subgraph->Invoke(operands); VLOG(DRIVER) << "XNNPACK subgraph invoke returned " << toString(status); - if (status == ErrorStatus::NONE) { + if (status == V1_3::ErrorStatus::NONE) { VLOG(DRIVER) << "Completed run normally"; for (auto& runtimeInfo : requestPoolInfos) { runtimeInfo.flush(); @@ -1639,25 +1664,26 @@ void asyncExecuteXNNPACK(Subgraph* subgraph, RunTimeOperandInfo* operands, const } template <typename T_IExecutionCallback> -ErrorStatus executeXNNPACKBase(Subgraph* subgraph, RunTimeOperandInfo* operands, - const Request& request, MeasureTiming measure, const Model& model, - const OptionalTimePoint& halDeadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const sp<T_IExecutionCallback>& callback) { +V1_3::ErrorStatus executeXNNPACKBase(Subgraph* subgraph, RunTimeOperandInfo* operands, + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::Model& model, + const V1_3::OptionalTimePoint& halDeadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const sp<T_IExecutionCallback>& callback) { VLOG(DRIVER) << "executeXNNPACKBase(" << SHOW_IF_DEBUG(toString(request)) << ")"; if (callback.get() == nullptr) { LOG(ERROR) << "invalid callback passed to executeXNNPACKBase"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (!validateRequest(request, model, /*allowUnspecifiedOutput=*/false)) { - notify(callback, ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming); - return ErrorStatus::INVALID_ARGUMENT; + notify(callback, V1_3::ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming); + return V1_3::ErrorStatus::INVALID_ARGUMENT; } const auto deadline = makeDeadline(halDeadline); if (hasDeadlinePassed(deadline)) { - notify(callback, ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming); - return ErrorStatus::NONE; + notify(callback, V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming); + return V1_3::ErrorStatus::NONE; } // This thread is intentionally detached because the sample driver service @@ -1668,60 +1694,63 @@ ErrorStatus executeXNNPACKBase(Subgraph* subgraph, RunTimeOperandInfo* operands, loopTimeoutDuration, callback); }).detach(); - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } -Return<V1_0::ErrorStatus> SamplePreparedModelXNNPACK::execute( +hardware::Return<V1_0::ErrorStatus> SamplePreparedModelXNNPACK::execute( const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) { - const Model* model = getModel(); - const ErrorStatus status = + const V1_3::Model* model = getModel(); + const V1_3::ErrorStatus status = executeXNNPACKBase(mSubgraph, mOperands.data(), convertToV1_3(request), - MeasureTiming::NO, *model, {}, {}, callback); + V1_2::MeasureTiming::NO, *model, {}, {}, callback); return convertToV1_0(status); } -Return<V1_0::ErrorStatus> SamplePreparedModelXNNPACK::execute_1_2( - const V1_0::Request& request, MeasureTiming measure, +hardware::Return<V1_0::ErrorStatus> SamplePreparedModelXNNPACK::execute_1_2( + const V1_0::Request& request, V1_2::MeasureTiming measure, const sp<V1_2::IExecutionCallback>& callback) { - const Model* model = getModel(); - const ErrorStatus status = executeXNNPACKBase( + const V1_3::Model* model = getModel(); + const V1_3::ErrorStatus status = executeXNNPACKBase( mSubgraph, mOperands.data(), convertToV1_3(request), measure, *model, {}, {}, callback); return convertToV1_0(status); } -Return<V1_3::ErrorStatus> SamplePreparedModelXNNPACK::execute_1_3( - const V1_3::Request& request, MeasureTiming measure, const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, +hardware::Return<V1_3::ErrorStatus> SamplePreparedModelXNNPACK::execute_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, const sp<V1_3::IExecutionCallback>& callback) { - const Model* model = getModel(); + const V1_3::Model* model = getModel(); return executeXNNPACKBase(mSubgraph, mOperands.data(), request, measure, *model, deadline, loopTimeoutDuration, callback); } -static std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> executeSynchronouslyXNNPACKBase( - Subgraph* subgraph, RunTimeOperandInfo* operands, const Request& request, - MeasureTiming measure, const Model& model, const OptionalTimePoint& halDeadline, - const OptionalTimeoutDuration& loopTimeoutDuration) { +static std::tuple<V1_3::ErrorStatus, hardware::hidl_vec<V1_2::OutputShape>, V1_2::Timing> +executeSynchronouslyXNNPACKBase(Subgraph* subgraph, RunTimeOperandInfo* operands, + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::Model& model, + const V1_3::OptionalTimePoint& halDeadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration) { VLOG(DRIVER) << "executeSynchronouslyXNNPACKBase(" << SHOW_IF_DEBUG(toString(request)) << ")"; if (!validateRequest(request, model, /*allowUnspecifiedOutput=*/false)) { - return {ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming}; + return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, kNoTiming}; } const auto deadline = makeDeadline(halDeadline); if (hasDeadlinePassed(deadline)) { - return {ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming}; + return {V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT, {}, kNoTiming}; } std::vector<RunTimePoolInfo> requestPoolInfos; - if (!setRunTimePoolInfosFromMemoryPools(&requestPoolInfos, request.pools)) { - return {ErrorStatus::GENERAL_FAILURE, {}, kNoTiming}; + if (!setRunTimePoolInfosFromMemoryPools(&requestPoolInfos, uncheckedConvert(request.pools))) { + return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming}; } updateForArguments(model.main.inputIndexes, request.inputs, requestPoolInfos, operands); updateForArguments(model.main.outputIndexes, request.outputs, requestPoolInfos, operands); VLOG(DRIVER) << "XNNPACK subgraph invoke started"; auto status = subgraph->Invoke(operands); VLOG(DRIVER) << "XNNPACK subgraph invoke returned " << toString(status); - if (status == ErrorStatus::NONE) { + if (status == V1_3::ErrorStatus::NONE) { VLOG(DRIVER) << "Completed run normally"; for (auto& runtimeInfo : requestPoolInfos) { runtimeInfo.flush(); @@ -1730,59 +1759,60 @@ static std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> executeSynchronous return {status, {}, kNoTiming}; } -Return<void> SamplePreparedModelXNNPACK::executeSynchronously(const V1_0::Request& request, - MeasureTiming measure, - executeSynchronously_cb cb) { - const Model* model = getModel(); +hardware::Return<void> SamplePreparedModelXNNPACK::executeSynchronously( + const V1_0::Request& request, V1_2::MeasureTiming measure, executeSynchronously_cb cb) { + const V1_3::Model* model = getModel(); auto [status, outputShapes, timing] = executeSynchronouslyXNNPACKBase( mSubgraph, mOperands.data(), convertToV1_3(request), measure, *model, {}, {}); cb(convertToV1_0(status), std::move(outputShapes), timing); - return Void(); + return hardware::Void(); } -Return<void> SamplePreparedModelXNNPACK::executeSynchronously_1_3( - const Request& request, MeasureTiming measure, const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb) { - const Model* model = getModel(); +hardware::Return<void> SamplePreparedModelXNNPACK::executeSynchronously_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb) { + const V1_3::Model* model = getModel(); auto [status, outputShapes, timing] = executeSynchronouslyXNNPACKBase( mSubgraph, mOperands.data(), request, measure, *model, deadline, loopTimeoutDuration); cb(status, std::move(outputShapes), timing); - return Void(); + return hardware::Void(); } // The sample driver will finish the execution and then return. -Return<void> SamplePreparedModelXNNPACK::executeFenced( - const Request& request, const hidl_vec<hidl_handle>& waitFor, MeasureTiming measure, - const OptionalTimePoint& halDeadline, const OptionalTimeoutDuration& loopTimeoutDuration, - const OptionalTimeoutDuration& duration, executeFenced_cb cb) { +hardware::Return<void> SamplePreparedModelXNNPACK::executeFenced( + const V1_3::Request& request, const hardware::hidl_vec<hardware::hidl_handle>& waitFor, + V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& halDeadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const V1_3::OptionalTimeoutDuration& duration, executeFenced_cb cb) { VLOG(DRIVER) << "executeFenced(" << SHOW_IF_DEBUG(toString(request)) << ")"; - const Model* model = getModel(); + const V1_3::Model* model = getModel(); if (!validateRequest(request, *model, /*allowUnspecifiedOutput=*/false)) { - cb(ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } const auto deadline = makeDeadline(halDeadline); if (hasDeadlinePassed(deadline)) { - cb(ErrorStatus::MISSED_DEADLINE_PERSISTENT, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } // Wait for the dependent events to signal for (const auto& fenceHandle : waitFor) { if (!fenceHandle.getNativeHandle()) { - cb(ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } int syncFenceFd = fenceHandle.getNativeHandle()->data[0]; if (syncWait(syncFenceFd, -1) != FenceState::SIGNALED) { LOG(ERROR) << "syncWait failed"; - cb(ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } } std::vector<RunTimePoolInfo> requestPoolInfos; - if (!setRunTimePoolInfosFromMemoryPools(&requestPoolInfos, request.pools)) { - cb(ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr); + if (!setRunTimePoolInfosFromMemoryPools(&requestPoolInfos, uncheckedConvert(request.pools))) { + cb(V1_3::ErrorStatus::GENERAL_FAILURE, hardware::hidl_handle(nullptr), nullptr); } updateForArguments(model->main.inputIndexes, request.inputs, requestPoolInfos, mOperands.data()); @@ -1790,7 +1820,7 @@ Return<void> SamplePreparedModelXNNPACK::executeFenced( mOperands.data()); auto status = mSubgraph->Invoke(mOperands.data()); VLOG(DRIVER) << "XNNPACK subgraph invoke returned " << toString(status); - if (status == ErrorStatus::NONE) { + if (status == V1_3::ErrorStatus::NONE) { VLOG(DRIVER) << "Completed run normally"; for (auto& runtimeInfo : requestPoolInfos) { runtimeInfo.flush(); @@ -1799,47 +1829,49 @@ Return<void> SamplePreparedModelXNNPACK::executeFenced( sp<SampleFencedExecutionCallback> fencedExecutionCallback = new SampleFencedExecutionCallback(kNoTiming, kNoTiming, status); - cb(status, hidl_handle(nullptr), fencedExecutionCallback); - return Void(); + cb(status, hardware::hidl_handle(nullptr), fencedExecutionCallback); + return hardware::Void(); } class SampleDriverFloatXNNPACK : public SampleDriverPartial { public: SampleDriverFloatXNNPACK() : SampleDriverPartial("nnapi-sample_float_xnnpack") {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback) override; - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& callback) override; - Return<V1_0::ErrorStatus> prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference preference, - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) override; - Return<ErrorStatus> prepareModel_1_3(const Model& model, ExecutionPreference preference, - Priority priority, const OptionalTimePoint& deadline, - const hidl_vec<hidl_handle>& modelCache, - const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, - const sp<IPreparedModelCallback>& callback) override; - Return<void> allocate(const V1_3::BufferDesc& desc, - const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, - const hidl_vec<V1_3::BufferRole>& inputRoles, - const hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) override; + hardware::Return<V1_0::ErrorStatus> prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_2::IPreparedModelCallback>& callback) override; + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_3::IPreparedModelCallback>& callback) override; + hardware::Return<void> allocate( + const V1_3::BufferDesc& desc, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, + const hardware::hidl_vec<V1_3::BufferRole>& inputRoles, + const hardware::hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) override; private: - std::vector<bool> getSupportedOperationsImpl(const Model& model) const override; + std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const override; }; template <typename T_Model, typename T_IPreparedModelCallback> -ErrorStatus prepareModelXNNPACK(const T_Model& model, const SampleDriver* driver, - ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, - const sp<T_IPreparedModelCallback>& callback) { +V1_3::ErrorStatus prepareModelXNNPACK(const T_Model& model, const SampleDriver* driver, + V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const sp<T_IPreparedModelCallback>& callback) { const uid_t userId = hardware::IPCThreadState::self()->getCallingUid(); if (callback.get() == nullptr) { LOG(ERROR) << "invalid callback passed to prepareModelBase"; - return ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (VLOG_IS_ON(DRIVER)) { VLOG(DRIVER) << "prepareModelBase"; @@ -1847,8 +1879,8 @@ ErrorStatus prepareModelXNNPACK(const T_Model& model, const SampleDriver* driver } if (!validateModel(model) || !validateExecutionPreference(preference) || !validatePriority(priority)) { - notify(callback, ErrorStatus::INVALID_ARGUMENT, nullptr); - return ErrorStatus::INVALID_ARGUMENT; + notify(callback, V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr); + return V1_3::ErrorStatus::INVALID_ARGUMENT; } // asynchronously prepare the model from a new, detached thread @@ -1856,77 +1888,81 @@ ErrorStatus prepareModelXNNPACK(const T_Model& model, const SampleDriver* driver sp<SamplePreparedModelXNNPACK> preparedModel = new SamplePreparedModelXNNPACK( convertToV1_3(model), driver, preference, userId, priority); if (!preparedModel->initialize()) { - notify(callback, ErrorStatus::INVALID_ARGUMENT, nullptr); + notify(callback, V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr); return; } - notify(callback, ErrorStatus::NONE, preparedModel); + notify(callback, V1_3::ErrorStatus::NONE, preparedModel); }).detach(); - return ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } -Return<V1_0::ErrorStatus> SampleDriverFloatXNNPACK::prepareModel( +hardware::Return<V1_0::ErrorStatus> SampleDriverFloatXNNPACK::prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback) { - const ErrorStatus status = prepareModelXNNPACK( - model, this, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, {}, callback); + const V1_3::ErrorStatus status = + prepareModelXNNPACK(model, this, V1_1::ExecutionPreference::FAST_SINGLE_ANSWER, + kDefaultPriority13, {}, callback); return convertToV1_0(status); } -Return<V1_0::ErrorStatus> SampleDriverFloatXNNPACK::prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, +hardware::Return<V1_0::ErrorStatus> SampleDriverFloatXNNPACK::prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& callback) { - const ErrorStatus status = - prepareModelXNNPACK(model, this, preference, kDefaultPriority, {}, callback); + const V1_3::ErrorStatus status = + prepareModelXNNPACK(model, this, preference, kDefaultPriority13, {}, callback); return convertToV1_0(status); } -Return<V1_0::ErrorStatus> SampleDriverFloatXNNPACK::prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference preference, const hidl_vec<hidl_handle>&, - const hidl_vec<hidl_handle>&, const CacheToken&, +hardware::Return<V1_0::ErrorStatus> SampleDriverFloatXNNPACK::prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const HalCacheToken&, const sp<V1_2::IPreparedModelCallback>& callback) { - const ErrorStatus status = - prepareModelXNNPACK(model, this, preference, kDefaultPriority, {}, callback); + const V1_3::ErrorStatus status = + prepareModelXNNPACK(model, this, preference, kDefaultPriority13, {}, callback); return convertToV1_0(status); } -Return<ErrorStatus> SampleDriverFloatXNNPACK::prepareModel_1_3( - const Model& model, ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache, - const hidl_vec<hidl_handle>& dataCache, const CacheToken& token, - const sp<IPreparedModelCallback>& callback) { +hardware::Return<V1_3::ErrorStatus> SampleDriverFloatXNNPACK::prepareModel_1_3( + const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_3::IPreparedModelCallback>& callback) { return prepareModelXNNPACK(model, this, preference, priority, deadline, callback); } -Return<void> SampleDriverFloatXNNPACK::getCapabilities_1_3(getCapabilities_1_3_cb cb) { +hardware::Return<void> SampleDriverFloatXNNPACK::getCapabilities_1_3(getCapabilities_1_3_cb cb) { android::nn::initVLogMask(); VLOG(DRIVER) << "SampleDriverFloatXNNPACK::getCapabilities()"; - Capabilities capabilities = { + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = {.execTime = 0.7f, .powerUsage = 1.1f}, .relaxedFloat32toFloat16PerformanceTensor = {.execTime = 0.7f, .powerUsage = 1.1f}, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>({1.0f, 1.0f}), .ifPerformance = {.execTime = 1.0f, .powerUsage = 1.0f}, .whilePerformance = {.execTime = 1.0f, .powerUsage = 1.0f}}; - update(&capabilities.operandPerformance, OperandType::TENSOR_FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32, {.execTime = 0.8f, .powerUsage = 1.2f}); - update(&capabilities.operandPerformance, OperandType::FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::FLOAT32, {.execTime = 0.8f, .powerUsage = 1.2f}); - cb(ErrorStatus::NONE, capabilities); - return Void(); + cb(V1_3::ErrorStatus::NONE, capabilities); + return hardware::Void(); } -std::vector<bool> SampleDriverFloatXNNPACK::getSupportedOperationsImpl(const Model& model) const { +std::vector<bool> SampleDriverFloatXNNPACK::getSupportedOperationsImpl( + const V1_3::Model& model) const { std::vector<RunTimePoolInfo> poolInfos; - setRunTimePoolInfosFromHidlMemories(&poolInfos, model.pools); + setRunTimePoolInfosFromCanonicalMemories(&poolInfos, uncheckedConvert(model.pools)); auto operands = initializeRunTimeInfo(model.main, poolInfos, &model.operandValues); const size_t count = model.main.operations.size(); std::vector<bool> supported(count); for (size_t i = 0; i < count; i++) { bool isSupportedOp = false; - const Operation& operation = model.main.operations[i]; + const V1_3::Operation& operation = model.main.operations[i]; if (Subgraph::VisitNode(/*subgraph=*/nullptr, operation, operands.data(), {}) == - ErrorStatus::NONE) { + V1_3::ErrorStatus::NONE) { isSupportedOp = true; } supported[i] = isSupportedOp; @@ -1934,14 +1970,15 @@ std::vector<bool> SampleDriverFloatXNNPACK::getSupportedOperationsImpl(const Mod return supported; } -Return<void> SampleDriverFloatXNNPACK::allocate( - const V1_3::BufferDesc& desc, const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, - const hidl_vec<V1_3::BufferRole>& inputRoles, const hidl_vec<V1_3::BufferRole>& outputRoles, - allocate_cb cb) { +hardware::Return<void> SampleDriverFloatXNNPACK::allocate( + const V1_3::BufferDesc& desc, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, + const hardware::hidl_vec<V1_3::BufferRole>& inputRoles, + const hardware::hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) { VLOG(DRIVER) << "SampleDriverFloatXNNPACK::allocate not supported"; constexpr uint32_t kInvalidBufferToken = 0; - cb(ErrorStatus::INVALID_ARGUMENT, nullptr, kInvalidBufferToken); - return Void(); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr, kInvalidBufferToken); + return hardware::Void(); } } // namespace sample_driver diff --git a/nn/driver/sample/SampleDriverFull.cpp b/nn/driver/sample/SampleDriverFull.cpp index e0f15eaa3..efd5e60a3 100644 --- a/nn/driver/sample/SampleDriverFull.cpp +++ b/nn/driver/sample/SampleDriverFull.cpp @@ -27,37 +27,35 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - -Return<void> SampleDriverFull::getCapabilities_1_3(getCapabilities_1_3_cb cb) { +hardware::Return<void> SampleDriverFull::getCapabilities_1_3(getCapabilities_1_3_cb cb) { android::nn::initVLogMask(); VLOG(DRIVER) << "getCapabilities_1_3()"; - Capabilities capabilities = { + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = mPerf, .relaxedFloat32toFloat16PerformanceTensor = mPerf, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>(mPerf), .ifPerformance = mPerf, .whilePerformance = mPerf}; - cb(ErrorStatus::NONE, capabilities); - return Void(); + cb(V1_3::ErrorStatus::NONE, capabilities); + return hardware::Void(); } -Return<void> SampleDriverFull::getSupportedOperations_1_3(const V1_3::Model& model, - getSupportedOperations_1_3_cb cb) { +hardware::Return<void> SampleDriverFull::getSupportedOperations_1_3( + const V1_3::Model& model, getSupportedOperations_1_3_cb cb) { VLOG(DRIVER) << "getSupportedOperations_1_3()"; if (validateModel(model)) { const size_t count = model.main.operations.size(); std::vector<bool> supported(count, true); for (size_t i = 0; i < count; i++) { - const Operation& operation = model.main.operations[i]; + const V1_3::Operation& operation = model.main.operations[i]; supported[i] = !isExtensionOperationType(operation.type); } - cb(ErrorStatus::NONE, supported); + cb(V1_3::ErrorStatus::NONE, supported); } else { std::vector<bool> supported; - cb(ErrorStatus::INVALID_ARGUMENT, supported); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, supported); } - return Void(); + return hardware::Void(); } } // namespace sample_driver diff --git a/nn/driver/sample/SampleDriverFull.h b/nn/driver/sample/SampleDriverFull.h index 155463a85..ecf5c76b0 100644 --- a/nn/driver/sample/SampleDriverFull.h +++ b/nn/driver/sample/SampleDriverFull.h @@ -26,14 +26,14 @@ namespace sample_driver { class SampleDriverFull : public SampleDriver { public: - SampleDriverFull(const char* name, hal::PerformanceInfo perf) + SampleDriverFull(const char* name, V1_0::PerformanceInfo perf) : SampleDriver(name), mPerf(perf) {} - hal::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; - hal::Return<void> getSupportedOperations_1_3(const hal::V1_3::Model& model, - getSupportedOperations_1_3_cb cb) override; + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model& model, + getSupportedOperations_1_3_cb cb) override; private: - hal::PerformanceInfo mPerf; + V1_0::PerformanceInfo mPerf; }; } // namespace sample_driver diff --git a/nn/driver/sample/SampleDriverMinimal.cpp b/nn/driver/sample/SampleDriverMinimal.cpp index 3b0f15d23..eef99374e 100644 --- a/nn/driver/sample/SampleDriverMinimal.cpp +++ b/nn/driver/sample/SampleDriverMinimal.cpp @@ -31,34 +31,32 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - class SampleDriverMinimal : public SampleDriverPartial { public: SampleDriverMinimal() : SampleDriverPartial("nnapi-sample_minimal") {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; private: std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const override; }; -Return<void> SampleDriverMinimal::getCapabilities_1_3(getCapabilities_1_3_cb cb) { +hardware::Return<void> SampleDriverMinimal::getCapabilities_1_3(getCapabilities_1_3_cb cb) { android::nn::initVLogMask(); VLOG(DRIVER) << "getCapabilities()"; - Capabilities capabilities = { + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = {.execTime = 0.4f, .powerUsage = 0.5f}, .relaxedFloat32toFloat16PerformanceTensor = {.execTime = 0.4f, .powerUsage = 0.5f}, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>({1.0f, 1.0f}), .ifPerformance = {.execTime = 1.0f, .powerUsage = 1.0f}, .whilePerformance = {.execTime = 1.0f, .powerUsage = 1.0f}}; - update(&capabilities.operandPerformance, OperandType::TENSOR_FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32, {.execTime = 0.4f, .powerUsage = 0.5f}); - update(&capabilities.operandPerformance, OperandType::FLOAT32, + update(&capabilities.operandPerformance, V1_3::OperandType::FLOAT32, {.execTime = 0.4f, .powerUsage = 0.5f}); - cb(ErrorStatus::NONE, capabilities); - return Void(); + cb(V1_3::ErrorStatus::NONE, capabilities); + return hardware::Void(); } std::vector<bool> SampleDriverMinimal::getSupportedOperationsImpl(const V1_3::Model& model) const { @@ -67,13 +65,13 @@ std::vector<bool> SampleDriverMinimal::getSupportedOperationsImpl(const V1_3::Mo // Simulate supporting just a few ops for (size_t i = 0; i < count; i++) { supported[i] = false; - const Operation& operation = model.main.operations[i]; + const V1_3::Operation& operation = model.main.operations[i]; switch (operation.type) { - case OperationType::ADD: - case OperationType::CONCATENATION: - case OperationType::CONV_2D: { - const Operand& firstOperand = model.main.operands[operation.inputs[0]]; - if (firstOperand.type == OperandType::TENSOR_FLOAT32) { + case V1_3::OperationType::ADD: + case V1_3::OperationType::CONCATENATION: + case V1_3::OperationType::CONV_2D: { + const V1_3::Operand& firstOperand = model.main.operands[operation.inputs[0]]; + if (firstOperand.type == V1_3::OperandType::TENSOR_FLOAT32) { supported[i] = true; } break; diff --git a/nn/driver/sample/SampleDriverPartial.cpp b/nn/driver/sample/SampleDriverPartial.cpp index 0430a8527..0c3b4d4c2 100644 --- a/nn/driver/sample/SampleDriverPartial.cpp +++ b/nn/driver/sample/SampleDriverPartial.cpp @@ -32,25 +32,23 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - -Return<void> SampleDriverPartial::getSupportedOperations_1_3(const V1_3::Model& model, - getSupportedOperations_1_3_cb cb) { +hardware::Return<void> SampleDriverPartial::getSupportedOperations_1_3( + const V1_3::Model& model, getSupportedOperations_1_3_cb cb) { VLOG(DRIVER) << "getSupportedOperations()"; if (validateModel(model)) { std::vector<bool> supported = getSupportedOperationsImpl(model); - cb(ErrorStatus::NONE, supported); + cb(V1_3::ErrorStatus::NONE, supported); } else { std::vector<bool> supported; - cb(ErrorStatus::INVALID_ARGUMENT, supported); + cb(V1_3::ErrorStatus::INVALID_ARGUMENT, supported); } - return Void(); + return hardware::Void(); } -Return<ErrorStatus> SampleDriverPartial::prepareModel_1_3( - const V1_3::Model& model, ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>&, - const hidl_vec<hidl_handle>&, const CacheToken&, +hardware::Return<V1_3::ErrorStatus> SampleDriverPartial::prepareModel_1_3( + const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const HalCacheToken&, const sp<V1_3::IPreparedModelCallback>& callback) { std::vector<bool> supported = getSupportedOperationsImpl(model); bool isModelFullySupported = diff --git a/nn/driver/sample/SampleDriverPartial.h b/nn/driver/sample/SampleDriverPartial.h index 9150a1eb3..953030c68 100644 --- a/nn/driver/sample/SampleDriverPartial.h +++ b/nn/driver/sample/SampleDriverPartial.h @@ -37,19 +37,19 @@ class SampleDriverPartial : public SampleDriver { SampleDriverPartial(const char* name, const IOperationResolver* operationResolver = BuiltinOperationResolver::get()) : SampleDriver(name, operationResolver) {} - hal::Return<void> getSupportedOperations_1_3(const hal::V1_3::Model& model, - getSupportedOperations_1_3_cb cb) override; - hal::Return<hal::ErrorStatus> prepareModel_1_3( - const hal::V1_3::Model& model, hal::ExecutionPreference preference, - hal::Priority priority, const hal::OptionalTimePoint& deadline, - const hal::hidl_vec<hal::hidl_handle>& modelCache, - const hal::hidl_vec<hal::hidl_handle>& dataCache, const hal::CacheToken& token, - const sp<hal::V1_3::IPreparedModelCallback>& callback) override; + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model& model, + getSupportedOperations_1_3_cb cb) override; + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_3::IPreparedModelCallback>& callback) override; protected: // Given a valid NNAPI Model returns a boolean vector that indicates which // ops in the model are supported by a driver. - virtual std::vector<bool> getSupportedOperationsImpl(const hal::V1_3::Model& model) const = 0; + virtual std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const = 0; }; } // namespace sample_driver diff --git a/nn/driver/sample/SampleDriverQuant.cpp b/nn/driver/sample/SampleDriverQuant.cpp index 91eb6e268..f73a6fd4b 100644 --- a/nn/driver/sample/SampleDriverQuant.cpp +++ b/nn/driver/sample/SampleDriverQuant.cpp @@ -31,47 +31,45 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - class SampleDriverQuant : public SampleDriverPartial { public: SampleDriverQuant() : SampleDriverPartial("nnapi-sample_quant") {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; private: std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const override; }; -Return<void> SampleDriverQuant::getCapabilities_1_3(getCapabilities_1_3_cb cb) { +hardware::Return<void> SampleDriverQuant::getCapabilities_1_3(getCapabilities_1_3_cb cb) { android::nn::initVLogMask(); VLOG(DRIVER) << "getCapabilities()"; - Capabilities capabilities = { + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = {.execTime = 50.0f, .powerUsage = 1.0f}, .relaxedFloat32toFloat16PerformanceTensor = {.execTime = 50.0f, .powerUsage = 1.0f}, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>({50.0f, 1.0f}), .ifPerformance = {.execTime = 50.0f, .powerUsage = 1.0f}, .whilePerformance = {.execTime = 50.0f, .powerUsage = 1.0f}}; - cb(ErrorStatus::NONE, capabilities); - return Void(); + cb(V1_3::ErrorStatus::NONE, capabilities); + return hardware::Void(); } -static bool isQuantized(OperandType opType) { - return opType == OperandType::TENSOR_QUANT8_ASYMM || - opType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED; +static bool isQuantized(V1_3::OperandType opType) { + return opType == V1_3::OperandType::TENSOR_QUANT8_ASYMM || + opType == V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED; } std::vector<bool> SampleDriverQuant::getSupportedOperationsImpl(const V1_3::Model& model) const { const size_t count = model.main.operations.size(); std::vector<bool> supported(count); for (size_t i = 0; i < count; i++) { - const Operation& operation = model.main.operations[i]; + const V1_3::Operation& operation = model.main.operations[i]; if (!isExtensionOperationType(operation.type) && operation.inputs.size() > 0) { - const Operand& firstOperand = model.main.operands[operation.inputs[0]]; + const V1_3::Operand& firstOperand = model.main.operands[operation.inputs[0]]; supported[i] = isQuantized(firstOperand.type); - if (operation.type == OperationType::SELECT) { - const Operand& secondOperand = model.main.operands[operation.inputs[1]]; + if (operation.type == V1_3::OperationType::SELECT) { + const V1_3::Operand& secondOperand = model.main.operands[operation.inputs[1]]; supported[i] = isQuantized(secondOperand.type); } } diff --git a/nn/driver/sample/SampleDriverUtils.cpp b/nn/driver/sample/SampleDriverUtils.cpp index 7cccf92e2..e8c571818 100644 --- a/nn/driver/sample/SampleDriverUtils.cpp +++ b/nn/driver/sample/SampleDriverUtils.cpp @@ -23,9 +23,7 @@ namespace android { namespace nn { namespace sample_driver { -using namespace hal; - -void notify(const sp<V1_0::IPreparedModelCallback>& callback, const ErrorStatus& status, +void notify(const sp<V1_0::IPreparedModelCallback>& callback, const V1_3::ErrorStatus& status, const sp<SamplePreparedModel>& preparedModel) { const auto ret = callback->notify(convertToV1_0(status), preparedModel); if (!ret.isOk()) { @@ -33,7 +31,7 @@ void notify(const sp<V1_0::IPreparedModelCallback>& callback, const ErrorStatus& } } -void notify(const sp<V1_2::IPreparedModelCallback>& callback, const ErrorStatus& status, +void notify(const sp<V1_2::IPreparedModelCallback>& callback, const V1_3::ErrorStatus& status, const sp<SamplePreparedModel>& preparedModel) { const auto ret = callback->notify_1_2(convertToV1_0(status), preparedModel); if (!ret.isOk()) { @@ -42,7 +40,7 @@ void notify(const sp<V1_2::IPreparedModelCallback>& callback, const ErrorStatus& } } -void notify(const sp<V1_3::IPreparedModelCallback>& callback, const ErrorStatus& status, +void notify(const sp<V1_3::IPreparedModelCallback>& callback, const V1_3::ErrorStatus& status, const sp<SamplePreparedModel>& preparedModel) { const auto ret = callback->notify_1_3(status, preparedModel); if (!ret.isOk()) { @@ -51,24 +49,24 @@ void notify(const sp<V1_3::IPreparedModelCallback>& callback, const ErrorStatus& } } -void notify(const sp<V1_0::IExecutionCallback>& callback, const ErrorStatus& status, - const hidl_vec<OutputShape>&, Timing) { +void notify(const sp<V1_0::IExecutionCallback>& callback, const V1_3::ErrorStatus& status, + const hardware::hidl_vec<V1_2::OutputShape>&, V1_2::Timing) { const auto ret = callback->notify(convertToV1_0(status)); if (!ret.isOk()) { LOG(ERROR) << "Error when calling IExecutionCallback::notify: " << ret.description(); } } -void notify(const sp<V1_2::IExecutionCallback>& callback, const ErrorStatus& status, - const hidl_vec<OutputShape>& outputShapes, Timing timing) { +void notify(const sp<V1_2::IExecutionCallback>& callback, const V1_3::ErrorStatus& status, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, V1_2::Timing timing) { const auto ret = callback->notify_1_2(convertToV1_0(status), outputShapes, timing); if (!ret.isOk()) { LOG(ERROR) << "Error when calling IExecutionCallback::notify_1_2: " << ret.description(); } } -void notify(const sp<V1_3::IExecutionCallback>& callback, const ErrorStatus& status, - const hidl_vec<OutputShape>& outputShapes, Timing timing) { +void notify(const sp<V1_3::IExecutionCallback>& callback, const V1_3::ErrorStatus& status, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, V1_2::Timing timing) { const auto ret = callback->notify_1_3(status, outputShapes, timing); if (!ret.isOk()) { LOG(ERROR) << "Error when calling IExecutionCallback::notify_1_3" << ret.description(); diff --git a/nn/driver/sample/SampleDriverUtils.h b/nn/driver/sample/SampleDriverUtils.h index d5a87a1e1..3a34239b2 100644 --- a/nn/driver/sample/SampleDriverUtils.h +++ b/nn/driver/sample/SampleDriverUtils.h @@ -25,34 +25,34 @@ namespace android { namespace nn { namespace sample_driver { -void notify(const sp<hal::V1_0::IPreparedModelCallback>& callback, const hal::ErrorStatus& status, +void notify(const sp<V1_0::IPreparedModelCallback>& callback, const V1_3::ErrorStatus& status, const sp<SamplePreparedModel>& preparedModel); -void notify(const sp<hal::V1_2::IPreparedModelCallback>& callback, const hal::ErrorStatus& status, +void notify(const sp<V1_2::IPreparedModelCallback>& callback, const V1_3::ErrorStatus& status, const sp<SamplePreparedModel>& preparedModel); -void notify(const sp<hal::V1_3::IPreparedModelCallback>& callback, const hal::ErrorStatus& status, +void notify(const sp<V1_3::IPreparedModelCallback>& callback, const V1_3::ErrorStatus& status, const sp<SamplePreparedModel>& preparedModel); -void notify(const sp<hal::V1_0::IExecutionCallback>& callback, const hal::ErrorStatus& status, - const hal::hidl_vec<hal::OutputShape>&, hal::Timing); +void notify(const sp<V1_0::IExecutionCallback>& callback, const V1_3::ErrorStatus& status, + const hardware::hidl_vec<V1_2::OutputShape>&, V1_2::Timing); -void notify(const sp<hal::V1_2::IExecutionCallback>& callback, const hal::ErrorStatus& status, - const hal::hidl_vec<hal::OutputShape>& outputShapes, hal::Timing timing); +void notify(const sp<V1_2::IExecutionCallback>& callback, const V1_3::ErrorStatus& status, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, V1_2::Timing timing); -void notify(const sp<hal::V1_3::IExecutionCallback>& callback, const hal::ErrorStatus& status, - const hal::hidl_vec<hal::OutputShape>& outputShapes, hal::Timing timing); +void notify(const sp<V1_3::IExecutionCallback>& callback, const V1_3::ErrorStatus& status, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, V1_2::Timing timing); template <typename T_Model, typename T_IPreparedModelCallback> -hal::ErrorStatus prepareModelBase(const T_Model& model, const SampleDriver* driver, - hal::ExecutionPreference preference, hal::Priority priority, - const hal::OptionalTimePoint& halDeadline, - const sp<T_IPreparedModelCallback>& callback, - bool isFullModelSupported = true) { +V1_3::ErrorStatus prepareModelBase(const T_Model& model, const SampleDriver* driver, + V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& halDeadline, + const sp<T_IPreparedModelCallback>& callback, + bool isFullModelSupported = true) { const uid_t userId = hardware::IPCThreadState::self()->getCallingUid(); if (callback.get() == nullptr) { LOG(ERROR) << "invalid callback passed to prepareModelBase"; - return hal::ErrorStatus::INVALID_ARGUMENT; + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (VLOG_IS_ON(DRIVER)) { VLOG(DRIVER) << "prepareModelBase"; @@ -60,17 +60,17 @@ hal::ErrorStatus prepareModelBase(const T_Model& model, const SampleDriver* driv } if (!validateModel(model) || !validateExecutionPreference(preference) || !validatePriority(priority)) { - notify(callback, hal::ErrorStatus::INVALID_ARGUMENT, nullptr); - return hal::ErrorStatus::INVALID_ARGUMENT; + notify(callback, V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr); + return V1_3::ErrorStatus::INVALID_ARGUMENT; } if (!isFullModelSupported) { - notify(callback, hal::ErrorStatus::INVALID_ARGUMENT, nullptr); - return hal::ErrorStatus::NONE; + notify(callback, V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr); + return V1_3::ErrorStatus::NONE; } const auto deadline = makeDeadline(halDeadline); if (hasDeadlinePassed(deadline)) { - notify(callback, hal::ErrorStatus::MISSED_DEADLINE_PERSISTENT, nullptr); - return hal::ErrorStatus::NONE; + notify(callback, V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT, nullptr); + return V1_3::ErrorStatus::NONE; } // asynchronously prepare the model from a new, detached thread @@ -78,13 +78,13 @@ hal::ErrorStatus prepareModelBase(const T_Model& model, const SampleDriver* driv sp<SamplePreparedModel> preparedModel = new SamplePreparedModel(convertToV1_3(model), driver, preference, userId, priority); if (!preparedModel->initialize()) { - notify(callback, hal::ErrorStatus::INVALID_ARGUMENT, nullptr); + notify(callback, V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr); return; } - notify(callback, hal::ErrorStatus::NONE, preparedModel); + notify(callback, V1_3::ErrorStatus::NONE, preparedModel); }).detach(); - return hal::ErrorStatus::NONE; + return V1_3::ErrorStatus::NONE; } } // namespace sample_driver diff --git a/nn/runtime/Callbacks.cpp b/nn/runtime/Callbacks.cpp index 6a81b9c14..d31098c89 100644 --- a/nn/runtime/Callbacks.cpp +++ b/nn/runtime/Callbacks.cpp @@ -18,28 +18,25 @@ #include "Callbacks.h" +#include <Utils.h> #include <android-base/logging.h> + #include <limits> #include <utility> #include <vector> namespace android::nn { -using namespace hal; - -constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(), - .timeInDriver = std::numeric_limits<uint64_t>::max()}; - // PreparedModelCallback methods begin here -Return<void> PreparedModelCallback::notifyInternal(bool deadObject, ErrorStatus errorStatus, - const sp<V1_0::IPreparedModel>& preparedModel) { +hardware::Return<void> PreparedModelCallback::notifyInternal( + bool deadObject, ErrorStatus errorStatus, const sp<V1_0::IPreparedModel>& preparedModel) { { std::lock_guard<std::mutex> hold(mMutex); // quick-return if object has already been notified if (mNotified) { - return Void(); + return hardware::Void(); } // store results and mark as notified @@ -50,22 +47,22 @@ Return<void> PreparedModelCallback::notifyInternal(bool deadObject, ErrorStatus } mCondition.notify_all(); - return Void(); + return hardware::Void(); } -Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus errorStatus, - const sp<V1_0::IPreparedModel>& preparedModel) { - return notifyInternal(false, static_cast<ErrorStatus>(errorStatus), preparedModel); +hardware::Return<void> PreparedModelCallback::notify( + V1_0::ErrorStatus errorStatus, const sp<V1_0::IPreparedModel>& preparedModel) { + return notifyInternal(false, uncheckedConvert(errorStatus), preparedModel); } -Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus errorStatus, - const sp<V1_2::IPreparedModel>& preparedModel) { - return notifyInternal(false, static_cast<ErrorStatus>(errorStatus), preparedModel); +hardware::Return<void> PreparedModelCallback::notify_1_2( + V1_0::ErrorStatus errorStatus, const sp<V1_2::IPreparedModel>& preparedModel) { + return notifyInternal(false, uncheckedConvert(errorStatus), preparedModel); } -Return<void> PreparedModelCallback::notify_1_3(ErrorStatus errorStatus, - const sp<V1_3::IPreparedModel>& preparedModel) { - return notifyInternal(false, errorStatus, preparedModel); +hardware::Return<void> PreparedModelCallback::notify_1_3( + V1_3::ErrorStatus errorStatus, const sp<V1_3::IPreparedModel>& preparedModel) { + return notifyInternal(false, uncheckedConvert(errorStatus), preparedModel); } void PreparedModelCallback::notifyAsDeadObject() { @@ -94,24 +91,26 @@ bool PreparedModelCallback::isDeadObject() const { // ExecutionCallback methods begin here -Return<void> ExecutionCallback::notify(V1_0::ErrorStatus errorStatus) { - return notifyInternal(false, static_cast<ErrorStatus>(errorStatus), {}, kNoTiming); +hardware::Return<void> ExecutionCallback::notify(V1_0::ErrorStatus errorStatus) { + return notifyInternal(false, uncheckedConvert(errorStatus), {}, {}); } -Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus errorStatus, - const hidl_vec<OutputShape>& outputShapes, - const Timing& timing) { - return notifyInternal(false, static_cast<ErrorStatus>(errorStatus), outputShapes, timing); +hardware::Return<void> ExecutionCallback::notify_1_2( + V1_0::ErrorStatus errorStatus, const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { + return notifyInternal(false, uncheckedConvert(errorStatus), uncheckedConvert(outputShapes), + uncheckedConvert(timing)); } -Return<void> ExecutionCallback::notify_1_3(V1_3::ErrorStatus errorStatus, - const hidl_vec<OutputShape>& outputShapes, - const Timing& timing) { - return notifyInternal(false, errorStatus, outputShapes, timing); +hardware::Return<void> ExecutionCallback::notify_1_3( + V1_3::ErrorStatus errorStatus, const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { + return notifyInternal(false, uncheckedConvert(errorStatus), uncheckedConvert(outputShapes), + uncheckedConvert(timing)); } void ExecutionCallback::notifyAsDeadObject() { - notifyInternal(true, ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + notifyInternal(true, ErrorStatus::GENERAL_FAILURE, {}, {}); } void ExecutionCallback::wait() const { @@ -199,9 +198,9 @@ void ExecutionCallback::setOnFinish(const ExecutionFinish& finish) { mOnFinish = finish; } -Return<void> ExecutionCallback::notifyInternal(bool deadObject, ErrorStatus errorStatus, - std::vector<OutputShape> outputShapes, - Timing timing) { +hardware::Return<void> ExecutionCallback::notifyInternal(bool deadObject, ErrorStatus errorStatus, + std::vector<OutputShape> outputShapes, + Timing timing) { // check results if (!deadObject) { if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { @@ -211,7 +210,7 @@ Return<void> ExecutionCallback::notifyInternal(bool deadObject, ErrorStatus erro << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; errorStatus = ErrorStatus::GENERAL_FAILURE; outputShapes = {}; - timing = kNoTiming; + timing = {}; } } else if (errorStatus != ErrorStatus::NONE) { // outputShapes must be empty if errorStatus is neither NONE nor @@ -221,7 +220,7 @@ Return<void> ExecutionCallback::notifyInternal(bool deadObject, ErrorStatus erro "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; errorStatus = ErrorStatus::GENERAL_FAILURE; outputShapes = {}; - timing = kNoTiming; + timing = {}; } } } @@ -232,7 +231,7 @@ Return<void> ExecutionCallback::notifyInternal(bool deadObject, ErrorStatus erro // quick-return if object has already been notified if (mNotified) { - return Void(); + return hardware::Void(); } mDeadObject = deadObject; @@ -250,7 +249,7 @@ Return<void> ExecutionCallback::notifyInternal(bool deadObject, ErrorStatus erro } } mCondition.notify_all(); - return Void(); + return hardware::Void(); } } // namespace android::nn diff --git a/nn/runtime/Callbacks.h b/nn/runtime/Callbacks.h index 75370254e..66408ce70 100644 --- a/nn/runtime/Callbacks.h +++ b/nn/runtime/Callbacks.h @@ -17,9 +17,11 @@ #ifndef ANDROID_FRAMEWORKS_ML_NN_RUNTIME_CALLBACKS_H #define ANDROID_FRAMEWORKS_ML_NN_RUNTIME_CALLBACKS_H -#include "HalInterfaces.h" - +#include <HalInterfaces.h> +#include <Utils.h> #include <android-base/thread_annotations.h> +#include <nnapi/Types.h> + #include <condition_variable> #include <functional> #include <mutex> @@ -60,7 +62,7 @@ namespace android::nn { * * This callback object is passed as an argument to IDevice::prepareModel*. */ -class PreparedModelCallback : public hal::IPreparedModelCallback { +class PreparedModelCallback : public V1_3::IPreparedModelCallback { public: /** * IPreparedModelCallback::notify marks the callback object with the return @@ -85,8 +87,8 @@ class PreparedModelCallback : public hal::IPreparedModelCallback { * @param preparedModel Returned model that has been prepared for execution, * nullptr if the model was unable to be prepared. */ - hal::Return<void> notify(hal::V1_0::ErrorStatus status, - const sp<hal::V1_0::IPreparedModel>& preparedModel) override; + hardware::Return<void> notify(V1_0::ErrorStatus status, + const sp<V1_0::IPreparedModel>& preparedModel) override; /** * IPreparedModelCallback::notify_1_2 marks the callback object with the @@ -111,8 +113,8 @@ class PreparedModelCallback : public hal::IPreparedModelCallback { * @param preparedModel Returned model that has been prepared for execution, * nullptr if the model was unable to be prepared. */ - hal::Return<void> notify_1_2(hal::V1_0::ErrorStatus status, - const sp<hal::V1_2::IPreparedModel>& preparedModel) override; + hardware::Return<void> notify_1_2(V1_0::ErrorStatus status, + const sp<V1_2::IPreparedModel>& preparedModel) override; /** * IPreparedModelCallback::notify_1_3 marks the callback object with the @@ -139,8 +141,8 @@ class PreparedModelCallback : public hal::IPreparedModelCallback { * @param preparedModel Returned model that has been prepared for execution, * nullptr if the model was unable to be prepared. */ - hal::Return<void> notify_1_3(hal::V1_3::ErrorStatus status, - const sp<hal::V1_3::IPreparedModel>& preparedModel) override; + hardware::Return<void> notify_1_3(V1_3::ErrorStatus status, + const sp<V1_3::IPreparedModel>& preparedModel) override; /** * Mark the callback object as a dead object. This acts as a call to notify. @@ -169,7 +171,7 @@ class PreparedModelCallback : public hal::IPreparedModelCallback { * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver * - DEAD_OBJECT if the driver crashed without returning a result */ - hal::V1_3::ErrorStatus getStatus() const; + ErrorStatus getStatus() const; /** * Retrieves the model that has been prepared for execution from the @@ -181,7 +183,7 @@ class PreparedModelCallback : public hal::IPreparedModelCallback { * @return preparedModel Returned model that has been prepared for * execution, nullptr if the model was unable to be prepared. */ - sp<hal::V1_0::IPreparedModel> getPreparedModel() const; + sp<V1_0::IPreparedModel> getPreparedModel() const; /** * Queries whether the object is dead. @@ -191,15 +193,15 @@ class PreparedModelCallback : public hal::IPreparedModelCallback { bool isDeadObject() const; private: - hal::Return<void> notifyInternal(bool deadObject, hal::ErrorStatus errorStatus, - const sp<hal::V1_0::IPreparedModel>& preparedModel); + hardware::Return<void> notifyInternal(bool deadObject, ErrorStatus errorStatus, + const sp<V1_0::IPreparedModel>& preparedModel); mutable std::mutex mMutex; mutable std::condition_variable mCondition; bool mNotified GUARDED_BY(mMutex) = false; bool mDeadObject = false; - hal::ErrorStatus mErrorStatus = hal::ErrorStatus::GENERAL_FAILURE; - sp<hal::V1_0::IPreparedModel> mPreparedModel; + ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; + sp<V1_0::IPreparedModel> mPreparedModel; }; /** @@ -216,9 +218,9 @@ class PreparedModelCallback : public hal::IPreparedModelCallback { * * This callback object is passed as an argument to IPreparedModel::execute*. */ -class ExecutionCallback : public hal::IExecutionCallback { +class ExecutionCallback : public V1_3::IExecutionCallback { using ExecutionFinish = - std::function<hal::ErrorStatus(hal::ErrorStatus, const std::vector<hal::OutputShape>&)>; + std::function<ErrorStatus(ErrorStatus, const std::vector<OutputShape>&)>; public: /** @@ -244,7 +246,7 @@ class ExecutionCallback : public hal::IExecutionCallback { * enough to store the resultant values * - INVALID_ARGUMENT if the input request is invalid */ - hal::Return<void> notify(hal::V1_0::ErrorStatus status) override; + hardware::Return<void> notify(V1_0::ErrorStatus status) override; /** * IExecutionCallback::notify_1_2 marks the callback object with the results @@ -279,9 +281,9 @@ class ExecutionCallback : public hal::IExecutionCallback { * reported as UINT64_MAX. A driver may choose to report any time as * UINT64_MAX, indicating that particular measurement is not available. */ - hal::Return<void> notify_1_2(hal::V1_0::ErrorStatus status, - const hal::hidl_vec<hal::OutputShape>& outputShapes, - const hal::Timing& timing) override; + hardware::Return<void> notify_1_2(V1_0::ErrorStatus status, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) override; /** * IExecutionCallback::notify_1_3 marks the callback object with the results @@ -318,15 +320,15 @@ class ExecutionCallback : public hal::IExecutionCallback { * reported as UINT64_MAX. A driver may choose to report any time as * UINT64_MAX, indicating that particular measurement is not available. */ - hal::Return<void> notify_1_3(hal::V1_3::ErrorStatus status, - const hal::hidl_vec<hal::OutputShape>& outputShapes, - const hal::Timing& timing) override; + hardware::Return<void> notify_1_3(V1_3::ErrorStatus status, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) override; // An overload of the latest notify interface to hide the version from ExecutionBuilder. - hal::Return<void> notify(hal::V1_3::ErrorStatus status, - const hal::hidl_vec<hal::OutputShape>& outputShapes, - const hal::Timing& timing) { - return notify_1_3(status, outputShapes, timing); + hardware::Return<void> notify(ErrorStatus status, const std::vector<OutputShape>& outputShapes, + const Timing& timing) { + return notify_1_3(convertToV1_3(status), convertToV1_2(outputShapes), + convertToV1_2(timing)); } /** @@ -362,7 +364,7 @@ class ExecutionCallback : public hal::IExecutionCallback { * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver * - DEAD_OBJECT if the driver crashed without returning a result */ - hal::V1_3::ErrorStatus getStatus() const; + ErrorStatus getStatus() const; /** * Retrieves the output shapes returned from the asynchronous task launched @@ -385,7 +387,7 @@ class ExecutionCallback : public hal::IExecutionCallback { * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has * at least one output operand that is not fully-specified. */ - const std::vector<hal::OutputShape>& getOutputShapes() const; + const std::vector<OutputShape>& getOutputShapes() const; /** * Retrieves the duration of execution of the asynchronous task launched by @@ -400,7 +402,7 @@ class ExecutionCallback : public hal::IExecutionCallback { * @return timing Duration of the execution. Every time must be UINT64_MAX * unless the status is NONE. */ - hal::Timing getTiming() const; + Timing getTiming() const; /** * ExecutionCallback::bindThread binds a thread to the ExecutionCallback @@ -461,9 +463,8 @@ class ExecutionCallback : public hal::IExecutionCallback { * before any call to wait or get* return. It then enables all prior and * future wait calls on the ExecutionCallback object to proceed. */ - hal::Return<void> notifyInternal(bool deadObject, hal::ErrorStatus errorStatus, - std::vector<hal::OutputShape> outputShapes, - hal::Timing timing); + hardware::Return<void> notifyInternal(bool deadObject, ErrorStatus errorStatus, + std::vector<OutputShape> outputShapes, Timing timing); // members mutable std::mutex mMutex; @@ -472,9 +473,9 @@ class ExecutionCallback : public hal::IExecutionCallback { ExecutionFinish mOnFinish GUARDED_BY(mMutex); bool mNotified GUARDED_BY(mMutex) = false; bool mDeadObject = false; - hal::ErrorStatus mErrorStatus = hal::ErrorStatus::GENERAL_FAILURE; - std::vector<hal::OutputShape> mOutputShapes; - hal::Timing mTiming = {}; + ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; + std::vector<OutputShape> mOutputShapes; + Timing mTiming = {}; }; } // namespace android::nn diff --git a/nn/runtime/CompilationBuilder.cpp b/nn/runtime/CompilationBuilder.cpp index 051ac886c..5d2d5db07 100644 --- a/nn/runtime/CompilationBuilder.cpp +++ b/nn/runtime/CompilationBuilder.cpp @@ -36,8 +36,6 @@ namespace android { namespace nn { -using namespace hal; - CompilationBuilder::CompilationBuilder(const ModelBuilder* model, const std::vector<std::shared_ptr<Device>>& devices, bool explicitDeviceList) diff --git a/nn/runtime/Event.h b/nn/runtime/Event.h index 982381a09..41b9a28e8 100644 --- a/nn/runtime/Event.h +++ b/nn/runtime/Event.h @@ -28,7 +28,7 @@ class IEvent { public: virtual ~IEvent() = default; virtual void wait() const = 0; - virtual hal::ErrorStatus getStatus() const = 0; + virtual ErrorStatus getStatus() const = 0; virtual int getSyncFenceFd(bool shouldDup) const = 0; }; @@ -40,7 +40,7 @@ class CallbackEvent : public IEvent { } void wait() const override { kExecutionCallback->wait(); } - hal::ErrorStatus getStatus() const override { return kExecutionCallback->getStatus(); } + ErrorStatus getStatus() const override { return kExecutionCallback->getStatus(); } // Always return -1 as this is not backed by a sync fence. int getSyncFenceFd(bool /*should_dup*/) const override { return -1; } @@ -51,7 +51,7 @@ class CallbackEvent : public IEvent { // The SyncFenceEvent wraps sync fence and IFencedExecutionCallback class SyncFenceEvent : public IEvent { public: - SyncFenceEvent(int sync_fence_fd, const sp<hal::IFencedExecutionCallback>& callback) + SyncFenceEvent(int sync_fence_fd, const sp<V1_3::IFencedExecutionCallback>& callback) : kFencedExecutionCallback(callback) { if (sync_fence_fd > 0) { // Dup the provided file descriptor @@ -69,18 +69,18 @@ class SyncFenceEvent : public IEvent { // Get the status of the event. // In case of syncWait error, query the dispatch callback for detailed // error status. - hal::ErrorStatus getStatus() const override { - auto error = hal::ErrorStatus::NONE; + ErrorStatus getStatus() const override { + auto error = ErrorStatus::NONE; if (mSyncFenceFd > 0 && syncWait(mSyncFenceFd, -1) != FenceState::SIGNALED) { - error = hal::ErrorStatus::GENERAL_FAILURE; + error = ErrorStatus::GENERAL_FAILURE; // If there is a callback available, use the callback to get the error code. if (kFencedExecutionCallback != nullptr) { - const hal::Return<void> ret = kFencedExecutionCallback->getExecutionInfo( - [&error](hal::ErrorStatus status, hal::Timing, hal::Timing) { - error = status; + const hardware::Return<void> ret = kFencedExecutionCallback->getExecutionInfo( + [&error](V1_3::ErrorStatus status, V1_2::Timing, V1_2::Timing) { + error = uncheckedConvert(status); }); if (!ret.isOk()) { - error = hal::ErrorStatus::GENERAL_FAILURE; + error = ErrorStatus::GENERAL_FAILURE; } } } @@ -102,7 +102,7 @@ class SyncFenceEvent : public IEvent { private: // TODO(b/148423931): used android::base::unique_fd instead. int mSyncFenceFd = -1; - const sp<hal::IFencedExecutionCallback> kFencedExecutionCallback; + const sp<V1_3::IFencedExecutionCallback> kFencedExecutionCallback; }; } // namespace android::nn diff --git a/nn/runtime/ExecutionBuilder.cpp b/nn/runtime/ExecutionBuilder.cpp index 8b6b81758..aaf2bbdb9 100644 --- a/nn/runtime/ExecutionBuilder.cpp +++ b/nn/runtime/ExecutionBuilder.cpp @@ -45,12 +45,10 @@ namespace android { namespace nn { -using namespace hal; - // Partial validation of output shapes returned from driver, to ensure they // conform to a very specific set of rules. static bool validateOutputShapesFromDriver(ErrorStatus executionStatus, const ModelBuilder* model, - const std::vector<hal::OutputShape>& shapes) { + const std::vector<OutputShape>& shapes) { // Enforces the following rules (some of which are from b/154054474): // - shapes vector is empty except in the case of NONE or OUTPUT_INSUFFICIENT_SIZE. // If the vector is not empty, it must have as many entries as the step model has outputs. @@ -61,21 +59,21 @@ static bool validateOutputShapesFromDriver(ErrorStatus executionStatus, const Mo switch (executionStatus) { case ErrorStatus::NONE: { NN_RET_CHECK(shapes.size() == 0 || shapes.size() == model->outputCount()) - << "With execution ErrorStatus " << toString(executionStatus) + << "With execution ErrorStatus " << executionStatus << " output shapes vector must be empty or of length " << model->outputCount() << " but has length " << shapes.size(); NN_RET_CHECK(std::all_of(shapes.begin(), shapes.end(), [](const OutputShape& shape) { return shape.isSufficient; })) - << "With execution ErrorStatus " << toString(executionStatus) + << "With execution ErrorStatus " << executionStatus << " at least one output shape is unexpectedly marked !isSufficient"; const TypeManager* tm = TypeManager::get(); for (uint32_t outputIndex = 0, outputCount = shapes.size(); outputIndex < outputCount; ++outputIndex) { - const hal::Operand& outputOperand = model->getOutputOperand(outputIndex); + const Operand& outputOperand = model->getOutputOperand(outputIndex); NN_RET_CHECK(!tm->isTensorType(outputOperand.type) || (shapes[outputIndex].dimensions.size() != 0)) - << "With execution ErrorStatus " << toString(executionStatus) << " output#" + << "With execution ErrorStatus " << executionStatus << " output#" << outputIndex << " shape unexpectedly has zero rank"; } @@ -83,18 +81,18 @@ static bool validateOutputShapesFromDriver(ErrorStatus executionStatus, const Mo } case ErrorStatus::OUTPUT_INSUFFICIENT_SIZE: { NN_RET_CHECK(shapes.size() == model->outputCount()) - << "With execution ErrorStatus " << toString(executionStatus) + << "With execution ErrorStatus " << executionStatus << " output shapes vector must be of length " << model->outputCount() << " but has length " << shapes.size(); NN_RET_CHECK(std::any_of(shapes.begin(), shapes.end(), [](const OutputShape& shape) { return !shape.isSufficient; })) - << "With execution ErrorStatus " << toString(executionStatus) + << "With execution ErrorStatus " << executionStatus << " at least one output shape must have been marked !isSufficient"; break; } default: { NN_RET_CHECK(shapes.size() == 0) - << "With execution ErrorStatus " << toString(executionStatus) + << "With execution ErrorStatus " << executionStatus << " output shapes vector must be empty but has length " << shapes.size(); break; } @@ -102,13 +100,11 @@ static bool validateOutputShapesFromDriver(ErrorStatus executionStatus, const Mo return true; } static bool validateOutputShapesFromDriver(int executionResultCode, const ModelBuilder* model, - const std::vector<hal::OutputShape>& shapes) { + const std::vector<OutputShape>& shapes) { return validateOutputShapesFromDriver(convertResultCodeToErrorStatus(executionResultCode), model, shapes); } -const Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; - static MeasureTiming measureTiming(const ExecutionBuilder* execution) { return execution->measureTiming() ? MeasureTiming::YES : MeasureTiming::NO; } @@ -117,7 +113,7 @@ static bool checkDimensionInfo(const Operand& operand, const ANeuralNetworksOper const char* tag, bool allowUnspecified) { if (newType != nullptr) { const Extension::OperandTypeInformation* info = nullptr; - if (isExtensionOperandType(operand.type)) { + if (isExtension(operand.type)) { NN_RET_CHECK(TypeManager::get()->getExtensionOperandTypeInfo(operand.type, &info)); } if (validateOperandType(*newType, info, tag, allowUnspecified) != @@ -220,7 +216,8 @@ int ExecutionBuilder::setInput(uint32_t index, const ANeuralNetworksOperandType* } int ExecutionBuilder::setInputFromMemory(uint32_t index, const ANeuralNetworksOperandType* type, - const Memory* memory, size_t offset, size_t length) { + const RuntimeMemory* memory, size_t offset, + size_t length) { // Should be similar to StepExecutor::setInputOrOutputFromMemory() if (mStarted) { @@ -297,7 +294,8 @@ int ExecutionBuilder::setOutput(uint32_t index, const ANeuralNetworksOperandType } int ExecutionBuilder::setOutputFromMemory(uint32_t index, const ANeuralNetworksOperandType* type, - const Memory* memory, size_t offset, size_t length) { + const RuntimeMemory* memory, size_t offset, + size_t length) { // Should be similar to StepExecutor::setInputOrOutputFromMemory() if (mStarted) { @@ -383,12 +381,12 @@ int ExecutionBuilder::getDuration(int32_t durationCode, uint64_t* duration) cons Timing timingFenced = timingLaunched; if (mFencedExecutionCallback != nullptr) { ErrorStatus status; - const Return<void> ret = mFencedExecutionCallback->getExecutionInfo( - [&status, &timingLaunched, &timingFenced](ErrorStatus error, Timing tLaunched, - Timing tFenced) { - status = error; - timingLaunched = tLaunched; - timingFenced = tFenced; + const hardware::Return<void> ret = mFencedExecutionCallback->getExecutionInfo( + [&status, &timingLaunched, &timingFenced]( + V1_3::ErrorStatus error, V1_2::Timing tLaunched, V1_2::Timing tFenced) { + status = uncheckedConvert(error); + timingLaunched = uncheckedConvert(tLaunched); + timingFenced = uncheckedConvert(tFenced); }); if (!ret.isOk()) { *duration = UINT64_MAX; @@ -546,7 +544,7 @@ cpuFallbackPartial(const ExecutionPlan& plan, std::shared_ptr<StepExecutor> executor; int n1 = plan.fallback(controller, &executor, nullptr, nullptr); if (n1 != ANEURALNETWORKS_NO_ERROR) { - return {n1, {}, kNoTiming, nullptr}; + return {n1, {}, {}, nullptr}; } CHECK(executor != nullptr); @@ -565,7 +563,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, VLOG(EXECUTION) << "ExecutionBuilder::compute (from plan, iteratively)"; std::vector<OutputShape> outputShapes = executionBuilder->getInitialOutputShapes(); - Timing timing = kNoTiming; + Timing timing; // Disallow CPU fallback when the ExecutionPlan is simple on CPU. allowCpuFallback &= !plan.isSimpleCpu(); @@ -589,7 +587,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, bool missedDeadline = n == ANEURALNETWORKS_MISSED_DEADLINE_TRANSIENT || n == ANEURALNETWORKS_MISSED_DEADLINE_PERSISTENT; if (allowCpuFallback && !missedDeadline) break; - executionCallback->notify(convertResultCodeToErrorStatus(n), {}, kNoTiming); + executionCallback->notify(convertResultCodeToErrorStatus(n), {}, {}); return; } @@ -636,7 +634,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, // - we didn't learn anything new about dynamic temporaries. // Neither of these is recoverable, so end execution. const ErrorStatus stepStatus = convertResultCodeToErrorStatus(stepN); - executionCallback->notify(stepStatus, outputShapes, kNoTiming); + executionCallback->notify(stepStatus, outputShapes, {}); return; } // Every main model output is of sufficient size. This implies that @@ -649,7 +647,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, // If CPU fallback is not allowed and there was an error, end execution. if (!allowCpuFallback) { const ErrorStatus stepStatus = convertResultCodeToErrorStatus(stepN); - executionCallback->notify(stepStatus, {}, kNoTiming); + executionCallback->notify(stepStatus, {}, {}); return; } @@ -658,7 +656,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, // (2) return from the function with an error if (executorIsCpu) { if (!plan.isSimple()) break; - executionCallback->notify(convertResultCodeToErrorStatus(stepN), {}, kNoTiming); + executionCallback->notify(convertResultCodeToErrorStatus(stepN), {}, {}); return; } @@ -706,7 +704,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, // - we didn't learn anything new about dynamic temporaries. // Neither of these is recoverable, so end execution. const ErrorStatus fallbackStatus = convertResultCodeToErrorStatus(fallbackN); - executionCallback->notify(fallbackStatus, outputShapes, kNoTiming); + executionCallback->notify(fallbackStatus, outputShapes, {}); return; } // Every main model output is of sufficient size. This implies @@ -718,7 +716,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, // Do not fallback twice if the ExecutionPlan is simple. if (plan.isSimple()) { const ErrorStatus fallbackStatus = convertResultCodeToErrorStatus(fallbackN); - executionCallback->notify(fallbackStatus, {}, kNoTiming); + executionCallback->notify(fallbackStatus, {}, {}); return; } @@ -748,7 +746,7 @@ static void asyncStartComputePartitioned(ExecutionBuilder* executionBuilder, // fence and the fenced compute callback returned from the last partition. // Any failed partition will result in the whole execution fallback to CPU if // allowCpuFallback is set to true. -static std::tuple<int, int, sp<hal::IFencedExecutionCallback>> startComputeFenced( +static std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>> startComputeFenced( ExecutionBuilder* executionBuilder, const ExecutionPlan& plan, std::shared_ptr<ExecutionPlan::Controller> controller, const std::vector<int>& waitFor, uint64_t timeoutDurationAfterFence, const std::optional<Deadline>& deadline, @@ -773,7 +771,7 @@ static std::tuple<int, int, sp<hal::IFencedExecutionCallback>> startComputeFence // Initiate waitForFds, syncFence for the first step. std::vector<int> waitForFds = waitFor; int syncFence = -1; - sp<hal::IFencedExecutionCallback> computeFencedCallback; + sp<V1_3::IFencedExecutionCallback> computeFencedCallback; while (true) { VLOG(EXECUTION) << "looking for next StepExecutor"; @@ -942,7 +940,7 @@ int ExecutionBuilder::compute(sp<ExecutionCallback>* synchronizationCallback, LOG(ERROR) << "ANeuralNetworksExecution_" << name() << " not all inputs specified"; return ANEURALNETWORKS_BAD_DATA; } else if (p.state() == ModelArgumentInfo::MEMORY) { - const Memory* memory = mMemories[p.locationAndLength().poolIndex]; + const RuntimeMemory* memory = mMemories[p.locationAndLength().poolIndex]; if (!memory->getValidator().validateInputDimensions(p.dimensions())) { return ANEURALNETWORKS_OP_FAILED; } @@ -1015,7 +1013,7 @@ std::vector<OutputShape> ExecutionBuilder::getInitialOutputShapes() const { std::vector<OutputShape> outputShapes(mOutputs.size()); std::transform(mOutputs.begin(), mOutputs.end(), outputShapes.begin(), [](const auto& x) -> OutputShape { - hidl_vec<uint32_t> dimensions; + std::vector<uint32_t> dimensions; if (x.state() != ModelArgumentInfo::HAS_NO_VALUE) { dimensions = x.dimensions(); } @@ -1067,7 +1065,7 @@ bool ExecutionBuilder::updateOutputShapes(ErrorStatus status, bool ExecutionBuilder::updateMemories() { for (const auto& output : mOutputs) { if (output.state() != ModelArgumentInfo::MEMORY) continue; - const Memory* memory = mMemories[output.locationAndLength().poolIndex]; + const RuntimeMemory* memory = mMemories[output.locationAndLength().poolIndex]; NN_RET_CHECK(memory->getValidator().updateMetadata({.dimensions = output.dimensions()})); } return true; @@ -1084,7 +1082,7 @@ ErrorStatus ExecutionBuilder::finishWithoutSyncFence(ErrorStatus status, bool success = status == ErrorStatus::NONE; for (const auto& output : mOutputs) { if (output.state() != ModelArgumentInfo::MEMORY) continue; - const Memory* memory = mMemories[output.locationAndLength().poolIndex]; + const RuntimeMemory* memory = mMemories[output.locationAndLength().poolIndex]; memory->getValidator().setInitialized(success); } switch (convertErrorStatusToResultCode(status)) { @@ -1124,7 +1122,7 @@ bool StepExecutor::updateOutputShapes(int executionResultCode, const std::vector if (VLOG_IS_ON(EXECUTION)) { for (const auto& shape : from) { - VLOG(EXECUTION) << "updateOutputShapes: " << toString(shape); + VLOG(EXECUTION) << "updateOutputShapes: " << shape; } } @@ -1233,8 +1231,8 @@ bool StepExecutor::updateOutputShapes(int executionResultCode, const std::vector StepExecutor::StepExecutor(ExecutionBuilder* executionBuilder, const ModelBuilder* model, std::shared_ptr<Device> device, - std::shared_ptr<PreparedModel> preparedModel, const ExecutionStep* step, - DynamicTemporaries* dynamicTemporaries) + std::shared_ptr<RuntimePreparedModel> preparedModel, + const ExecutionStep* step, DynamicTemporaries* dynamicTemporaries) : mExecutionBuilder(executionBuilder), mExecutionStep(step), mDynamicTemporaries(dynamicTemporaries), @@ -1261,7 +1259,7 @@ void StepExecutor::mapInputsAndOutputsTrivially() { void StepExecutor::mapInputOrOutput(const ModelArgumentInfo& builderInputOrOutput, ModelArgumentInfo* executorInputOrOutput, - const hidl_vec<uint32_t>* builderDimensions) { + const Dimensions* builderDimensions) { auto updateDimensions = [executorInputOrOutput, builderDimensions] { if (!builderDimensions) { return; @@ -1283,7 +1281,7 @@ void StepExecutor::mapInputOrOutput(const ModelArgumentInfo& builderInputOrOutpu case ModelArgumentInfo::MEMORY: { updateDimensions(); const uint32_t builderPoolIndex = builderInputOrOutput.locationAndLength().poolIndex; - const Memory* memory = mExecutionBuilder->mMemories[builderPoolIndex]; + const RuntimeMemory* memory = mExecutionBuilder->mMemories[builderPoolIndex]; const uint32_t executorPoolIndex = mMemories.add(memory); executorInputOrOutput->locationAndLength().poolIndex = executorPoolIndex; break; @@ -1292,8 +1290,8 @@ void StepExecutor::mapInputOrOutput(const ModelArgumentInfo& builderInputOrOutpu } int StepExecutor::setInputOrOutputFromMemory(const Operand& inputOrOutputOperand, - const Memory* memory, uint32_t offset, - const hal::hidl_vec<uint32_t>& dimensions, + const RuntimeMemory* memory, uint32_t offset, + const Dimensions& dimensions, std::optional<uint32_t> length, ModelArgumentInfo* inputOrOutputInfo) { // Should be similar to @@ -1361,12 +1359,6 @@ bool StepExecutor::isCpu() const { return mDevice == DeviceManager::getCpuDevice(); } -static OptionalTimeoutDuration makeTimeoutDuration(uint64_t nanoseconds) { - OptionalTimeoutDuration otd; - otd.nanoseconds(nanoseconds); - return otd; -} - std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::compute( const std::optional<Deadline>& deadline, const std::shared_ptr<ExecutionBurstController>& burstController) { @@ -1374,7 +1366,7 @@ std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::compute( } std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::computeWithMemories( - const std::optional<Deadline>& deadline, const std::vector<const Memory*>& memories, + const std::optional<Deadline>& deadline, const std::vector<const RuntimeMemory*>& memories, const std::shared_ptr<ExecutionBurstController>& burstController) { CHECK(mPreparedModel != nullptr); @@ -1393,7 +1385,7 @@ std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::computeWithMemor return {n, std::move(outputShapes), timing}; } -std::tuple<int, int, sp<hal::IFencedExecutionCallback>> StepExecutor::computeFenced( +std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>> StepExecutor::computeFenced( const std::vector<int>& waitFor, uint64_t timeoutDurationAfterFence, const std::optional<Deadline>& deadline) { CHECK(mPreparedModel != nullptr); @@ -1408,7 +1400,7 @@ std::tuple<int, int, sp<hal::IFencedExecutionCallback>> StepExecutor::computeFen makeTimeoutDuration(mExecutionBuilder->getLoopTimeoutDuration()); OptionalTimeoutDuration optionalTimeoutDurationAfterFence; if (timeoutDurationAfterFence > 0) { - optionalTimeoutDurationAfterFence.nanoseconds(timeoutDurationAfterFence); + optionalTimeoutDurationAfterFence = makeTimeoutDuration(timeoutDurationAfterFence); } const auto [n, syncFence, computeFencedCallback, timing] = mPreparedModel->executeFenced( mInputs, mOutputs, mMemories.getObjects(), waitFor, measure, deadline, @@ -1425,24 +1417,24 @@ std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::computeOnCpuFall VLOG(EXECUTION) << "Re-compile the model on CPU"; mDevice = DeviceManager::getCpuDevice(); mPreparedModel = nullptr; - const ModelFactory makeModel = [this] { return mModel->makeHidlModel(); }; + const ModelFactory makeModel = [this] { return mModel->makeModel(); }; // TODO: Propagate user preference and compilation priority to this point instead of using // default values of ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER and // ANEURALNETWORKS_PRIORITY_MEDIUM const ExecutionPreference preference = static_cast<ExecutionPreference>(ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER); - const Priority priority = convertToHalPriority(ANEURALNETWORKS_PRIORITY_DEFAULT); + const Priority priority = convertToCanonicalPriority(ANEURALNETWORKS_PRIORITY_DEFAULT); auto [n, preparedModel] = mDevice->prepareModel(makeModel, preference, priority, {}, {}, {}); mPreparedModel = std::move(preparedModel); if (n != ANEURALNETWORKS_NO_ERROR) { - return {n, {}, kNoTiming}; + return {n, {}, {}}; } // Prepare device memories for CPU fallback. - std::vector<const Memory*> memories = mMemories.getObjects(); + std::vector<const RuntimeMemory*> memories = mMemories.getObjects(); std::vector<bool> isUsedAsInput(memories.size(), false); std::vector<bool> isUsedAsOutput(memories.size(), false); - std::vector<std::unique_ptr<Memory>> blobAhwbs; + std::vector<std::unique_ptr<RuntimeMemory>> blobAhwbs; // Mark the input and output usages. for (auto& input : mInputs) { @@ -1458,7 +1450,7 @@ std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::computeOnCpuFall if (mMemories[poolIndex]->getValidator().createdWithUnknownShape()) { LOG(ERROR) << "Cannot fallback to CPU because at least one of the output operands " "has unknown shape."; - return {ANEURALNETWORKS_OP_FAILED, {}, kNoTiming}; + return {ANEURALNETWORKS_OP_FAILED, {}, {}}; } isUsedAsOutput[poolIndex] = true; } @@ -1466,17 +1458,17 @@ std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::computeOnCpuFall // Allocate BLOB mode AHardwareBuffers and read the data from input device memories. for (uint32_t i = 0; i < memories.size(); i++) { - const Memory* memory = mMemories[i]; + const RuntimeMemory* memory = mMemories[i]; if (memory->getIBuffer() != nullptr) { const uint32_t size = memory->getValidator().getMetadata().logicalSize; auto [nAhwb, blobAhwb] = MemoryRuntimeAHWB::create(size); if (nAhwb != ANEURALNETWORKS_NO_ERROR) { - return {nAhwb, {}, kNoTiming}; + return {nAhwb, {}, {}}; } if (isUsedAsInput[i]) { n = copyIBufferToHidlMemory(memory->getIBuffer(), blobAhwb->getHidlMemory()); if (n != ANEURALNETWORKS_NO_ERROR) { - return {n, {}, kNoTiming}; + return {n, {}, {}}; } } memories[i] = blobAhwb.get(); @@ -1491,11 +1483,11 @@ std::tuple<int, std::vector<OutputShape>, Timing> StepExecutor::computeOnCpuFall // Write back to output device memories. for (uint32_t i = 0; i < memories.size(); i++) { - const Memory* memory = mMemories[i]; + const RuntimeMemory* memory = mMemories[i]; if (memory->getIBuffer() != nullptr && isUsedAsOutput[i]) { n = copyHidlMemoryToIBuffer(memories[i]->getHidlMemory(), memory->getIBuffer(), {}); if (n != ANEURALNETWORKS_NO_ERROR) { - return {n, {}, kNoTiming}; + return {n, {}, {}}; } } } diff --git a/nn/runtime/ExecutionBuilder.h b/nn/runtime/ExecutionBuilder.h index 2540f233c..1dbfce6bb 100644 --- a/nn/runtime/ExecutionBuilder.h +++ b/nn/runtime/ExecutionBuilder.h @@ -43,9 +43,9 @@ class DynamicTemporaries; class ExecutionBurstController; class ExecutionPlan; class ExecutionStep; -class Memory; class ModelBuilder; -class PreparedModel; +class RuntimeMemory; +class RuntimePreparedModel; class StepExecutor; class ExecutionBuilder { @@ -57,11 +57,11 @@ class ExecutionBuilder { int setInput(uint32_t index, const ANeuralNetworksOperandType* type, const void* buffer, size_t length); int setInputFromMemory(uint32_t index, const ANeuralNetworksOperandType* type, - const Memory* memory, size_t offset, size_t length); + const RuntimeMemory* memory, size_t offset, size_t length); int setOutput(uint32_t index, const ANeuralNetworksOperandType* type, void* buffer, size_t length); int setOutputFromMemory(uint32_t index, const ANeuralNetworksOperandType* type, - const Memory* memory, size_t offset, size_t length); + const RuntimeMemory* memory, size_t offset, size_t length); int setMeasureTiming(bool measure); @@ -86,30 +86,29 @@ class ExecutionBuilder { int burstCompute(BurstBuilder* burst) { return compute(nullptr, burst); } // Initialize output dimensional information from ModelArgumentInfo. - std::vector<hal::OutputShape> getInitialOutputShapes() const; + std::vector<OutputShape> getInitialOutputShapes() const; int getOutputOperandDimensions(uint32_t index, uint32_t* dimensions); int getOutputOperandRank(uint32_t index, uint32_t* rank); // Handshake with lower-level execution support bool measureTiming() const { return mMeasureTiming; } - void reportTimingWithoutFencedExecutionCallback(hal::Timing timing) { + void reportTimingWithoutFencedExecutionCallback(Timing timing) { mTimingWithoutFencedExecutionCallback = timing; } const CompilationBuilder* getCompilation() const { return mCompilation; } const ModelBuilder* getModel() const { return mModel; } const ModelBuilder* getSourceModel(uint32_t index) const; - const hal::Operand& getSourceOperand( - const std::pair<uint32_t, uint32_t>& sourceOperandIndex) const { + const Operand& getSourceOperand(const std::pair<uint32_t, uint32_t>& sourceOperandIndex) const { return getSourceModel(sourceOperandIndex.first)->getOperand(sourceOperandIndex.second); } - hal::ErrorStatus finishWithoutSyncFence(hal::ErrorStatus error, - const std::vector<hal::OutputShape>& outputShapes); + ErrorStatus finishWithoutSyncFence(ErrorStatus error, + const std::vector<OutputShape>& outputShapes); // Retrieve a reference to the IFencedExecutionCallback callback. - const sp<hal::IFencedExecutionCallback>& getFencedExecutionCallback() { + const sp<V1_3::IFencedExecutionCallback>& getFencedExecutionCallback() { return mFencedExecutionCallback; } @@ -136,8 +135,7 @@ class ExecutionBuilder { const CompilationBuilder* mCompilation; // Update output dimensional information from OutputShape to ModelArgumentInfo. - bool updateOutputShapes(hal::ErrorStatus status, - const std::vector<hal::OutputShape>& outputShapes); + bool updateOutputShapes(ErrorStatus status, const std::vector<OutputShape>& outputShapes); bool updateMemories(); @@ -153,7 +151,7 @@ class ExecutionBuilder { // The information we'll send to the driver about the inputs and outputs. // Note that we build this in two steps: // 1. As the arguments are specified, set the corresponding mInputs or mOutputs element. - // If set from a pointer, don't set the location in the RequestArgument but store it + // If set from a pointer, don't set the location in the Request::Argument but store it // instead in mInputBuffers or mOutputBuffers. // 2. Once we have all the inputs and outputs, if needed, allocate shared memory for // the m*Buffers entries. Copy the input values into the shared memory. @@ -169,7 +167,7 @@ class ExecutionBuilder { // Timing reported from the driver. This field is only used if // mFencedExecutionCallback is nullptr. - hal::Timing mTimingWithoutFencedExecutionCallback = {}; + Timing mTimingWithoutFencedExecutionCallback = {}; // Amount of time to complete or abort the execution. std::optional<uint64_t> mTimeoutDuration; @@ -207,7 +205,7 @@ class ExecutionBuilder { // doesn't support fenced execution (e.g., the driver is too old), or if the // launch of execution on the driver fails, then this callback will be // nullptr. - sp<hal::IFencedExecutionCallback> mFencedExecutionCallback; + sp<V1_3::IFencedExecutionCallback> mFencedExecutionCallback; }; // class StepExecutor is used to execute a single "step" in a @@ -236,7 +234,8 @@ class StepExecutor { // of "step" models. Must be nullptr otherwise. // (step == nullptr) == (dynamicTemporaries == nullptr) StepExecutor(ExecutionBuilder* executionBuilder, const ModelBuilder* model, - std::shared_ptr<Device> device, std::shared_ptr<PreparedModel> preparedModel, + std::shared_ptr<Device> device, + std::shared_ptr<RuntimePreparedModel> preparedModel, const ExecutionStep* step = nullptr, DynamicTemporaries* dynamicTemporaries = nullptr); @@ -255,8 +254,8 @@ class StepExecutor { bool zeroSizedInput; // is at least one output of this execution step a zero-sized tensor // that needs to be read by some other step of the same execution? }; - bool updateOutputShapes(int executionResultCode, const std::vector<hal::OutputShape>& from, - std::vector<hal::OutputShape>* to, UpdateOutputShapes* update); + bool updateOutputShapes(int executionResultCode, const std::vector<OutputShape>& from, + std::vector<OutputShape>* to, UpdateOutputShapes* update); // Map inputs and outputs from ExecutionBuilder to StepExecutor, // one at a time. Note that these are input/output indexes, not @@ -271,7 +270,7 @@ class StepExecutor { mapInputOrOutput(mExecutionBuilder->mOutputs[builderIndex], &mOutputs[executorIndex]); } void mapOutputToInput(uint32_t builderIndex, uint32_t executorIndex, - const hal::hidl_vec<uint32_t>* outputDimensions) { + const Dimensions* outputDimensions) { mapInputOrOutput(mExecutionBuilder->mOutputs[builderIndex], &mInputs[executorIndex], outputDimensions); } @@ -282,33 +281,33 @@ class StepExecutor { // (i.e., either rank must match, or operand rank must be zero; and for each // individual dimension, either dimension must match, or operand dimension // must be zero). - int setInputFromMemory(uint32_t inputIndex, const Memory* memory, uint32_t offset, - const hal::hidl_vec<uint32_t>& dimensions = {}, + int setInputFromMemory(uint32_t inputIndex, const RuntimeMemory* memory, uint32_t offset, + const Dimensions& dimensions = {}, std::optional<uint32_t> length = std::nullopt) { return setInputOrOutputFromMemory(mModel->getInputOperand(inputIndex), memory, offset, dimensions, length, &mInputs.at(inputIndex)); } - int setOutputFromMemory(uint32_t outputIndex, const Memory* memory, uint32_t offset, - const hal::hidl_vec<uint32_t>& dimensions = {}, + int setOutputFromMemory(uint32_t outputIndex, const RuntimeMemory* memory, uint32_t offset, + const Dimensions& dimensions = {}, std::optional<uint32_t> length = std::nullopt) { return setInputOrOutputFromMemory(mModel->getOutputOperand(outputIndex), memory, offset, dimensions, length, &mOutputs.at(outputIndex)); } // Executes using the (driver, preparedModel) specified at construction time. - std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> compute( + std::tuple<int, std::vector<OutputShape>, Timing> compute( const std::optional<Deadline>& deadline, const std::shared_ptr<ExecutionBurstController>& burstController = nullptr); // Re-compiles and executes using the CPU, regardless of the (driver, // preparedModel) specified at construction time. - std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> computeOnCpuFallback(); + std::tuple<int, std::vector<OutputShape>, Timing> computeOnCpuFallback(); bool isCpu() const; // Perform fenced execution and return error_code, sync_fence_fd and a // callback. - std::tuple<int, int, sp<hal::IFencedExecutionCallback>> computeFenced( + std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>> computeFenced( const std::vector<int>& wait_for, uint64_t timeoutDurationAfterFence, const std::optional<Deadline>& deadline); @@ -321,7 +320,7 @@ class StepExecutor { // specified dimensions. void mapInputOrOutput(const ModelArgumentInfo& builderInputOrOutput, ModelArgumentInfo* executorInputOrOutput, - const hal::hidl_vec<uint32_t>* builderDimensions = nullptr); + const Dimensions* builderDimensions = nullptr); // If no length is provided, the input or output is assumed to have the length // of the corresponding operand. dimensions must either have zero rank or @@ -329,13 +328,14 @@ class StepExecutor { // dimensions (i.e., either rank must match, or operand rank must be zero; // and for each individual dimension, either dimension must match, or // operand dimension must be zero). - int setInputOrOutputFromMemory(const hal::Operand& inputOrOutputOperand, const Memory* memory, - uint32_t offset, const hal::hidl_vec<uint32_t>& dimensions, + int setInputOrOutputFromMemory(const Operand& inputOrOutputOperand, const RuntimeMemory* memory, + uint32_t offset, const Dimensions& dimensions, std::optional<uint32_t> length, ModelArgumentInfo* inputOrOutputInfo); - std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> computeWithMemories( - const std::optional<Deadline>& deadline, const std::vector<const Memory*>& memories, + std::tuple<int, std::vector<OutputShape>, Timing> computeWithMemories( + const std::optional<Deadline>& deadline, + const std::vector<const RuntimeMemory*>& memories, const std::shared_ptr<ExecutionBurstController>& burstController = nullptr); // describes the full (possibly multiple-"step") execution @@ -351,12 +351,12 @@ class StepExecutor { // compiled forms; and device on which to execute it const ModelBuilder* mModel; std::shared_ptr<Device> mDevice; - std::shared_ptr<PreparedModel> mPreparedModel; + std::shared_ptr<RuntimePreparedModel> mPreparedModel; // The information we'll send to the driver about the inputs and outputs. // Note that we build this in two steps: // 1. As the arguments are specified, set the corresponding mInputs or mOutputs element. - // If set from a pointer, don't set the location in the RequestArgument but store it + // If set from a pointer, don't set the location in the Request::Argument but store it // instead in mInputBuffers or mOutputBuffers. // 2. Once we have all the inputs and outputs, if needed, allocate shared memory for // the m*Buffers entries. Copy the input values into the shared memory. diff --git a/nn/runtime/ExecutionPlan.cpp b/nn/runtime/ExecutionPlan.cpp index c3aa61f92..ba6911607 100644 --- a/nn/runtime/ExecutionPlan.cpp +++ b/nn/runtime/ExecutionPlan.cpp @@ -58,8 +58,6 @@ namespace nn { namespace { -using namespace hal; - // The index of the main model in SourceModels. constexpr uint32_t kMainModelInSourceModels = 0; @@ -71,7 +69,7 @@ constexpr uint32_t kMainModelInSourceModels = 0; int compile(const Device& device, const ModelBuilder& model, int executionPreference, int compilationPriority, const std::optional<Deadline>& deadline, const std::string& cacheDir, TokenHasher* token, - std::shared_ptr<PreparedModel>* preparedModel) { + std::shared_ptr<RuntimePreparedModel>* preparedModel) { CHECK(token != nullptr); CHECK(preparedModel != nullptr); *preparedModel = nullptr; @@ -82,12 +80,14 @@ int compile(const Device& device, const ModelBuilder& model, int executionPrefer token->updateFromString(device.getVersionString().c_str()) && token->update(&executionPreference, sizeof(executionPreference)) && token->update(&compilationPriority, sizeof(compilationPriority)) && token->finish()) { - cacheToken.emplace(token->getCacheToken()); + cacheToken = CacheToken{}; + const uint8_t* tokenPtr = token->getCacheToken(); + std::copy(tokenPtr, tokenPtr + cacheToken->size(), cacheToken->begin()); } - const ModelFactory makeModel = [&model] { return model.makeHidlModel(); }; + const ModelFactory makeModel = [&model] { return model.makeModel(); }; const ExecutionPreference preference = static_cast<ExecutionPreference>(executionPreference); - const Priority priority = convertToHalPriority(compilationPriority); + const Priority priority = convertToCanonicalPriority(compilationPriority); const auto [n, returnedPreparedModel] = device.prepareModel(makeModel, preference, priority, deadline, cacheDir, cacheToken); *preparedModel = returnedPreparedModel; @@ -99,27 +99,24 @@ typedef std::function<void(uint32_t)> OperationReadyCallback; int copyOperandExtraParams(ModelBuilder& model, uint32_t toOperandIndex, const Operand& fromOperand) { if (fromOperand.type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL && - fromOperand.extraParams.getDiscriminator() == - OperandExtraParams::hidl_discriminator::channelQuant) { - auto& fromChannelQuant = fromOperand.extraParams.channelQuant(); + std::holds_alternative<Operand::SymmPerChannelQuantParams>(fromOperand.extraParams)) { + auto& fromChannelQuant = + std::get<Operand::SymmPerChannelQuantParams>(fromOperand.extraParams); ANeuralNetworksSymmPerChannelQuantParams toChannelQuant = { .channelDim = fromChannelQuant.channelDim, .scaleCount = static_cast<uint32_t>(fromChannelQuant.scales.size()), .scales = fromChannelQuant.scales.data(), }; return model.setOperandSymmPerChannelQuantParams(toOperandIndex, toChannelQuant); - } else if (isExtensionOperandType(fromOperand.type) && - fromOperand.extraParams.getDiscriminator() == - OperandExtraParams::hidl_discriminator::extension) { - hidl_vec<uint8_t> extensionData = fromOperand.extraParams.extension(); + } else if (isExtension(fromOperand.type) && + std::holds_alternative<Operand::ExtensionParams>(fromOperand.extraParams)) { + auto extensionData = std::get<Operand::ExtensionParams>(fromOperand.extraParams); return model.setOperandExtensionData(toOperandIndex, extensionData.data(), extensionData.size()); - } else if (fromOperand.extraParams.getDiscriminator() != - OperandExtraParams::hidl_discriminator::none || + } else if (!std::holds_alternative<Operand::NoParams>(fromOperand.extraParams) || fromOperand.type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) { - LOG(ERROR) << "Type " << toString(fromOperand.type) - << " has an unexpected extraParams discriminator: " - << static_cast<int>(fromOperand.extraParams.getDiscriminator()); + LOG(ERROR) << "Type " << fromOperand.type + << " has an unexpected extraParams variant: " << fromOperand.extraParams.index(); return ANEURALNETWORKS_BAD_DATA; } else { return ANEURALNETWORKS_NO_ERROR; @@ -153,8 +150,8 @@ OperandTracker::OperandTracker(const ModelBuilder* model, OperationReadyCallback uint32_t count = 0; for (uint32_t operandIndex : operation.inputs) { auto lifetime = mModel->getOperand(operandIndex).lifetime; - if (lifetime == OperandLifeTime::TEMPORARY_VARIABLE || - lifetime == OperandLifeTime::SUBGRAPH_OUTPUT) { + if (lifetime == Operand::LifeTime::TEMPORARY_VARIABLE || + lifetime == Operand::LifeTime::SUBGRAPH_OUTPUT) { count++; mOperandToOperations.emplace(operandIndex, operationIndex); } @@ -193,21 +190,6 @@ std::string toString(SourceOperandIndex sourceOperandIndex) { std::to_string(sourceOperandIndex.second) + ")"; }; -std::string toString(hidl_vec<uint32_t> dimensions) { - std::string ret = "("; - bool wroteOne = false; - for (uint32_t dimension : dimensions) { - if (wroteOne) { - ret += ", "; - } else { - wroteOne = true; - } - ret += std::to_string(dimension); - } - ret += ")"; - return ret; -}; - } // namespace void DynamicTemporaries::vlogDump(const char* context) const { @@ -227,8 +209,7 @@ void DynamicTemporaries::vlogDump(const char* context) const { } void DynamicTemporaries::declare(SourceOperandIndex sourceOperandIndex, uint32_t stepIndex, - const hidl_vec<uint32_t>& initialDimensions, - uint32_t initialLength) { + const Dimensions& initialDimensions, uint32_t initialLength) { VLOG(EXECUTION) << "DynamicTemporaries::declare(sourceOperandIndex = " << toString(sourceOperandIndex) << ", stepIndex = " << stepIndex << ", initialDimensions = " << toString(initialDimensions) @@ -243,7 +224,7 @@ void DynamicTemporaries::declare(SourceOperandIndex sourceOperandIndex, uint32_t } bool DynamicTemporaries::redeclare(SourceOperandIndex sourceOperandIndex, - const hidl_vec<uint32_t>& newDimensions, uint32_t newLength) { + const Dimensions& newDimensions, uint32_t newLength) { auto createAndLogResult = [sourceOperandIndex, &newDimensions, newLength](bool changedShape) { VLOG(EXECUTION) << "DynamicTemporaries::redeclare(sourceOperandIndex = " << toString(sourceOperandIndex) @@ -389,31 +370,19 @@ int ExecutionStep::addOperand(uint32_t sourceOperandIndex, uint32_t* stepOperand // Sets its value. switch (operand.lifetime) { - case OperandLifeTime::CONSTANT_COPY: { + case Operand::LifeTime::CONSTANT_COPY: { const uint8_t* data = sourceModel.getPointerToOperandValue(operand.location.offset); n = mStepModel.setOperandValue(*stepOperandIndex, data, operand.location.length); - if (n != ANEURALNETWORKS_NO_ERROR) { - LOG(ERROR) << "Previous error occurred when partitioning the graph"; - return n; - } } break; - case OperandLifeTime::CONSTANT_REFERENCE: { - const Memory* memory = sourceModel.getMemories()[operand.location.poolIndex]; + case Operand::LifeTime::CONSTANT_REFERENCE: { + const RuntimeMemory* memory = sourceModel.getMemories()[operand.location.poolIndex]; n = mStepModel.setOperandValueFromMemory( *stepOperandIndex, memory, operand.location.offset, operand.location.length); - if (n != ANEURALNETWORKS_NO_ERROR) { - LOG(ERROR) << "Previous error occurred when partitioning the graph"; - return n; - } } break; - case OperandLifeTime::NO_VALUE: { + case Operand::LifeTime::NO_VALUE: { n = mStepModel.setOperandValue(*stepOperandIndex, nullptr, 0); - if (n != ANEURALNETWORKS_NO_ERROR) { - LOG(ERROR) << "Previous error occurred when partitioning the graph"; - return n; - } } break; - case OperandLifeTime::TEMPORARY_VARIABLE: { // handled similarly to SUBGRAPH_OUTPUT + case Operand::LifeTime::TEMPORARY_VARIABLE: { // handled similarly to SUBGRAPH_OUTPUT if (kind == INPUT) { // The first time we've seen this operand is as an // input. That means it must be defined by a @@ -427,10 +396,10 @@ int ExecutionStep::addOperand(uint32_t sourceOperandIndex, uint32_t* stepOperand mIndex); } } break; - case OperandLifeTime::SUBGRAPH_INPUT: { + case Operand::LifeTime::SUBGRAPH_INPUT: { mModelInputs.emplace_back(sourceOperandIndex, *stepOperandIndex); } break; - case OperandLifeTime::SUBGRAPH_OUTPUT: { // handled similarly to TEMPORARY_VARIABLE + case Operand::LifeTime::SUBGRAPH_OUTPUT: { // handled similarly to TEMPORARY_VARIABLE if (kind == INPUT) { // The first time we've seen this operand is as an // input. That means it must be defined by a @@ -446,20 +415,20 @@ int ExecutionStep::addOperand(uint32_t sourceOperandIndex, uint32_t* stepOperand mIndex); } } break; - case OperandLifeTime::SUBGRAPH: { + case Operand::LifeTime::SUBGRAPH: { const ModelBuilder* model = sourceModel.getReferencedModel(operand); n = mStepModel.setOperandValueFromModel(*stepOperandIndex, model); - if (n != ANEURALNETWORKS_NO_ERROR) { - LOG(ERROR) << "Previous error occurred when partitioning the graph"; - return n; - } } break; - default: { - CHECK(!"unexpected"); + case Operand::LifeTime::POINTER: { + const void* data = std::get<const void*>(operand.location.pointer); + n = mStepModel.setOperandValue(*stepOperandIndex, data, operand.location.length); } break; } - return ANEURALNETWORKS_NO_ERROR; + if (n != ANEURALNETWORKS_NO_ERROR) { + LOG(ERROR) << "Previous error occurred when partitioning the graph"; + } + return n; } int ExecutionStep::addOperation(int operationIndex) { @@ -477,7 +446,7 @@ int ExecutionStep::addOperation(int operationIndex) { // constant, or an operand written by a different partition. // // - We should not have seen any outputs. - auto addOperands = [this](const hidl_vec<uint32_t>& sourceModelOperands, + auto addOperands = [this](const std::vector<uint32_t>& sourceModelOperands, std::vector<uint32_t>* stepModelOperands, OperandKind kind) -> int { const uint32_t operandCount = static_cast<uint32_t>(sourceModelOperands.size()); for (uint32_t i = 0; i < operandCount; i++) { @@ -498,7 +467,7 @@ int ExecutionStep::addOperation(int operationIndex) { void ExecutionStep::mapInputsAndOutputs( std::shared_ptr<StepExecutor> executor, - const std::vector<hal::OutputShape>* mainModelOutputShapes, const Memory* temporaryMemory, + const std::vector<OutputShape>* mainModelOutputShapes, const RuntimeMemory* temporaryMemory, const std::map<SourceOperandIndex, uint32_t>& sourceOperandToOffsetOfTemporary, const DynamicTemporaries& dynamicTemporaries, const std::map<SourceOperandIndex, uint32_t>& sourceOperandToInputIndex, @@ -674,10 +643,10 @@ void ExecutionStep::logStepModel() const { } static bool hasUnknownSize(const Operand& operand) { - if (operand.dimensions.size() == 0) { + if (operand.dimensions.empty()) { return TypeManager::get()->isTensorType(operand.type); } - for (uint32_t dimension : operand.dimensions) { + for (const Dimension& dimension : operand.dimensions) { if (dimension == 0) { return true; } @@ -693,8 +662,8 @@ int ExecutionStep::finishStepModel(const ModelBuilder* mainModel, bool* hasOutpu const Operand& operand = mStepModel.getOperand(stepModelOutput.second); if (hasUnknownSize(operand)) { *hasOutputOfUnknownSize = true; - VLOG(COMPILATION) << "StepModelOutput (operand#" << toString(stepModelOutput.first) - << " of source graph) has unknown size: " << toString(operand); + VLOG(COMPILATION) << "StepModelOutput (operand#" << stepModelOutput.first + << " of source graph) has unknown size: " << operand; } } @@ -779,38 +748,32 @@ int ExecutionStep::finishStepModel(const ModelBuilder* mainModel, bool* hasOutpu void ExecutionStep::dump() const { if (VLOG_IS_ON(COMPILATION)) { VLOG(COMPILATION) << "Step#" << mIndex << ": execute on " << mDevice->getName(); - logModelToInfo(mStepModel.makeHidlModel()); + logModelToInfo(mStepModel.makeModel()); } } -std::string toString(const IfStep& step) { - std::ostringstream oss; - oss << "Step#" << step.index << ": if " << toString(step.conditionOperandIndex) - << " then=" << step.thenStepIndex << " else=" << step.elseStepIndex; - return oss.str(); +std::ostream& operator<<(std::ostream& os, const IfStep& step) { + return os << "Step#" << step.index << ": if " << toString(step.conditionOperandIndex) + << " then=" << step.thenStepIndex << " else=" << step.elseStepIndex; } -std::string toString(const WhileStep& step) { - std::ostringstream oss; - oss << "Step#" << step.index << ": while cond=" << step.condStepIndex - << " body=" << step.bodyStepIndex << " exit=" << step.exitStepIndex; - return oss.str(); +std::ostream& operator<<(std::ostream& os, const WhileStep& step) { + return os << "Step#" << step.index << ": while cond=" << step.condStepIndex + << " body=" << step.bodyStepIndex << " exit=" << step.exitStepIndex; } -std::string toString(const GotoStep& step) { - std::ostringstream oss; - oss << "Step#" << step.index << ": goto " << step.gotoStepIndex; - return oss.str(); +std::ostream& operator<<(std::ostream& os, const GotoStep& step) { + return os << "Step#" << step.index << ": goto " << step.gotoStepIndex; } void LogicalStep::dump() const { if (VLOG_IS_ON(COMPILATION)) { if (const IfStep* step = tryIfStep()) { - VLOG(COMPILATION) << toString(*step); + VLOG(COMPILATION) << *step; } else if (const WhileStep* step = tryWhileStep()) { - VLOG(COMPILATION) << toString(*step); + VLOG(COMPILATION) << *step; } else if (const GotoStep* step = tryGotoStep()) { - VLOG(COMPILATION) << toString(*step); + VLOG(COMPILATION) << *step; } else { executionStep()->dump(); } @@ -897,12 +860,17 @@ void ExecutionPlan::CompoundBody::findControlFlowBoundaryConstants( const ModelBuilder* sourceModel = sourceModels->getModel(sourceOperandIndex.first); const Operand& operand = sourceModel->getOperand(sourceOperandIndex.second); const DataLocation& location = operand.location; - if (operand.lifetime == OperandLifeTime::CONSTANT_COPY) { + if (operand.lifetime == Operand::LifeTime::CONSTANT_COPY) { mSourceOperandToBoundaryConstantCopy[sourceOperandIndex] = { .buffer = sourceModel->getPointerToOperandValue(location.offset), .length = location.length, }; - } else if (operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE) { + } else if (operand.lifetime == Operand::LifeTime::POINTER) { + mSourceOperandToBoundaryConstantCopy[sourceOperandIndex] = { + .buffer = static_cast<const uint8_t*>(std::get<const void*>(location.pointer)), + .length = location.length, + }; + } else if (operand.lifetime == Operand::LifeTime::CONSTANT_REFERENCE) { mSourceOperandToBoundaryConstantReference[sourceOperandIndex] = { .memory = sourceModel->getMemories()[location.poolIndex], .offset = location.offset, @@ -1043,7 +1011,7 @@ std::shared_ptr<ExecutionPlan::Controller> ExecutionPlan::makeController( if (mState == SIMPLE) { return std::shared_ptr<Controller>(new Controller(this, executionBuilder, burstBuilder)); } - // Create the layout for a Memory object big enough to hold + // Create the layout for a RuntimeMemory object big enough to hold // - every partition boundary TEMPORARY operand that is not a dynamic temporary, and // - buffers required by the control flow implementation. // @@ -1078,17 +1046,17 @@ std::shared_ptr<ExecutionPlan::Controller> ExecutionPlan::makeController( [executionBuilder, &totalSizeOfTemporaries]( const SourceOperandIndex& sourceOperandIndex, std::map<SourceOperandIndex, uint32_t>* sourceOperandToOffsetOfTemporary, - OperandLifeTime lifetime = OperandLifeTime::TEMPORARY_VARIABLE) { - CHECK(lifetime == OperandLifeTime::TEMPORARY_VARIABLE || - lifetime == OperandLifeTime::SUBGRAPH_OUTPUT); + Operand::LifeTime lifetime = Operand::LifeTime::TEMPORARY_VARIABLE) { + CHECK(lifetime == Operand::LifeTime::TEMPORARY_VARIABLE || + lifetime == Operand::LifeTime::SUBGRAPH_OUTPUT); const Operand& sourceOperand = executionBuilder->getSourceOperand(sourceOperandIndex); - if (lifetime == OperandLifeTime::TEMPORARY_VARIABLE && - sourceOperand.lifetime == OperandLifeTime::SUBGRAPH_OUTPUT) { + if (lifetime == Operand::LifeTime::TEMPORARY_VARIABLE && + sourceOperand.lifetime == Operand::LifeTime::SUBGRAPH_OUTPUT) { // See the caller for explanation. return; } - CHECK(sourceOperand.lifetime == lifetime); + CHECK_EQ(sourceOperand.lifetime, lifetime); const uint32_t size = TypeManager::get()->getSizeOfData(sourceOperand); if (size != 0u) { const uint32_t offset = addTemporaryOfSize(&totalSizeOfTemporaries, size); @@ -1100,8 +1068,8 @@ std::shared_ptr<ExecutionPlan::Controller> ExecutionPlan::makeController( } else { // Unknown size, hence dynamic temporary. The mapping will // be established elsewhere (DynamicTemporaries::allocate()). - CHECK(lifetime == OperandLifeTime::TEMPORARY_VARIABLE); - CHECK(sourceOperand.lifetime == OperandLifeTime::TEMPORARY_VARIABLE); + CHECK_EQ(lifetime, Operand::LifeTime::TEMPORARY_VARIABLE); + CHECK_EQ(sourceOperand.lifetime, Operand::LifeTime::TEMPORARY_VARIABLE); } }; std::map<SourceOperandIndex, uint32_t> sourceOperandToOffsetOfTemporary; @@ -1170,15 +1138,15 @@ std::shared_ptr<ExecutionPlan::Controller> ExecutionPlan::makeController( // so (b/148206073). for (const auto& sourceOperandIndex : step->bodyOutputOperands) { mapTemporary(sourceOperandIndex, &sourceOperandToOffsetOfTemporary, - OperandLifeTime::SUBGRAPH_OUTPUT); + Operand::LifeTime::SUBGRAPH_OUTPUT); // Allocate another set of temporaries for double buffering. mapTemporary(sourceOperandIndex, &sourceOperandToOffsetOfTemporary2, - OperandLifeTime::SUBGRAPH_OUTPUT); + Operand::LifeTime::SUBGRAPH_OUTPUT); } // Allocate memory for condition model output. // TODO: Share one condition output memory region between all loops. mapTemporary(step->condOutputOperand, &sourceOperandToOffsetOfTemporary, - OperandLifeTime::SUBGRAPH_OUTPUT); + Operand::LifeTime::SUBGRAPH_OUTPUT); } else { CHECK(logicalStep->isGoto()); } @@ -1245,7 +1213,7 @@ int ExecutionPlan::fallback(std::shared_ptr<Controller> controller, } ExecutionPlan::Buffer::Buffer(void* pointer, uint32_t size) - : mInfo(RunTimePoolInfo::createFromExistingBuffer(reinterpret_cast<uint8_t*>(pointer), size)), + : mInfo(RunTimePoolInfo::createFromExistingBuffer(static_cast<uint8_t*>(pointer), size)), mOffset(0) {} ExecutionPlan::Buffer::Buffer(RunTimePoolInfo info, uint32_t offset) @@ -1515,7 +1483,7 @@ int ExecutionPlan::nextCompound(const IfStep* step, std::shared_ptr<Controller> std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, const std::vector<OutputShape>* mainModelOutputShapes) const { - VLOG(EXECUTION) << "next: " << toString(*step); + VLOG(EXECUTION) << "next: " << *step; // If the last step has a sync fence, wait for it to signal before reading the condition value. // This is safe because the steps are serialized when doing fenced compute. NN_RETURN_IF_ERROR(controller->waitForLastStepSyncFence()); @@ -1558,7 +1526,7 @@ int ExecutionPlan::nextCompound(const WhileStep* step, std::shared_ptr<Controlle WhileState& state = controller->mWhileState[controller->mNextStepIndex]; if (state.stage == WhileState::EVALUATE_CONDITION) { state.iteration = state.iteration == WhileState::kOutsideLoop ? 0 : state.iteration + 1; - VLOG(EXECUTION) << "next: " << toString(*step) << ": iteration " << state.iteration + VLOG(EXECUTION) << "next: " << *step << ": iteration " << state.iteration << ": evaluating condition"; controller->mNextStepIndex = step->condStepIndex; @@ -1602,7 +1570,7 @@ int ExecutionPlan::nextCompound(const WhileStep* step, std::shared_ptr<Controlle bool condValue; NN_RETURN_IF_ERROR(readConditionValue(controller, step->condOutputOperand, &condValue)); if (condValue) { - VLOG(EXECUTION) << "next: " << toString(*step) << ": iteration " << state.iteration + VLOG(EXECUTION) << "next: " << *step << ": iteration " << state.iteration << ": evaluating body"; controller->mNextStepIndex = step->bodyStepIndex; @@ -1632,7 +1600,7 @@ int ExecutionPlan::nextCompound(const WhileStep* step, std::shared_ptr<Controlle } } } else { - VLOG(EXECUTION) << "next: " << toString(*step) << ": iteration " << state.iteration + VLOG(EXECUTION) << "next: " << *step << ": iteration " << state.iteration << ": exiting loop"; controller->mNextStepIndex = step->exitStepIndex; @@ -1677,7 +1645,7 @@ int ExecutionPlan::nextCompound(const GotoStep* step, std::shared_ptr<Controller std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, const std::vector<OutputShape>* mainModelOutputShapes) const { - VLOG(EXECUTION) << "next: " << toString(*step); + VLOG(EXECUTION) << "next: " << *step; controller->mNextStepIndex = step->gotoStepIndex; return nextCompound(controller, executor, burstController, mainModelOutputShapes); } @@ -1905,7 +1873,7 @@ int ModelBuilder::partitionTheWork(const std::vector<std::shared_ptr<Device>>& d int n = plan->finish(preference, priority, deadline, simulateFailureResultCode); if (VLOG_IS_ON(COMPILATION)) { VLOG(COMPILATION) << "ModelBuilder::partitionTheWork: source model: "; - logModelToInfo(makeHidlModel()); + logModelToInfo(makeModel()); plan->dump(); } return n; @@ -2148,7 +2116,7 @@ int ModelBuilder::partitionTheWorkInternal(uint32_t sourceModelIndex, bodyModelIndex, bodyModel->getOutputOperandIndex(i)); } } else { - CHECK(false) << toString(operation.type) << " is not a control flow operation"; + CHECK(false) << operation.type << " is not a control flow operation"; } tracker.markProcessed(operationIndex, enqueueOnAppropriateDevice); } @@ -2176,7 +2144,7 @@ float ModelBuilder::getPerformance(uint32_t preference, float ModelBuilder::getPerformance(uint32_t preference, const std::shared_ptr<Device> device, uint32_t operationIndex) const { - auto applyPreference = [preference](const PerformanceInfo& perf) { + auto applyPreference = [preference](const Capabilities::PerformanceInfo& perf) { return preference == ANEURALNETWORKS_PREFER_LOW_POWER ? perf.powerUsage : perf.execTime; }; @@ -2300,7 +2268,7 @@ class CanDo { int ModelBuilder::findBestDeviceForEachOperation( uint32_t preference, const std::vector<std::shared_ptr<Device>>& devices, std::vector<int>* bestDeviceForOperation) const { - const MetaModel metaModel(makeHidlModel(), DeviceManager::get()->strictSlicing()); + const MetaModel metaModel(makeModel(), DeviceManager::get()->strictSlicing()); const size_t deviceCount = devices.size(); std::vector<CanDo> canDo(deviceCount); @@ -2345,13 +2313,13 @@ int ModelBuilder::findBestDeviceForEachOperation( // Logs O(operationCount * deviceCount) times, but typically deviceCount is // very small. VLOG(COMPILATION) << "Device " << device->getName() << " can't do operation " - << toString(operation.type); + << operation.type; } } } if (bestChoice < 0) { - LOG(ERROR) << "No driver can do operation " << toString(operation.type); + LOG(ERROR) << "No driver can do operation " << operation.type; return ANEURALNETWORKS_BAD_DATA; } else if (devices[bestChoice] == DeviceManager::getCpuDevice() && supportedByControlFlowInterpreter(operationIndex)) { @@ -2359,15 +2327,13 @@ int ModelBuilder::findBestDeviceForEachOperation( // to delegate referenced models. const int kControlFlowInterpreter = deviceCount; (*bestDeviceForOperation)[operationIndex] = kControlFlowInterpreter; - VLOG(COMPILATION) << "ModelBuilder::findBestDeviceForEachOperation(" - << toString(operation.type) << ":" << operationIndex << ") = -1" - << " (NNAPI)"; + VLOG(COMPILATION) << "ModelBuilder::findBestDeviceForEachOperation(" << operation.type + << operation.type << ":" << operationIndex << ") = -1 (NNAPI)"; } else { (*bestDeviceForOperation)[operationIndex] = bestChoice; - VLOG(COMPILATION) << "ModelBuilder::findBestDeviceForEachOperation(" - << toString(operation.type) << ":" << operationIndex - << ") = " << bestChoice << " (" << devices[bestChoice]->getName() - << ")"; + VLOG(COMPILATION) << "ModelBuilder::findBestDeviceForEachOperation(" << operation.type + << ":" << operationIndex << ") = " << bestChoice << " (" + << devices[bestChoice]->getName() << ")"; } } return ANEURALNETWORKS_NO_ERROR; diff --git a/nn/runtime/ExecutionPlan.h b/nn/runtime/ExecutionPlan.h index 740912d8e..097fbd600 100644 --- a/nn/runtime/ExecutionPlan.h +++ b/nn/runtime/ExecutionPlan.h @@ -20,6 +20,7 @@ #define ANDROID_FRAMEWORKS_ML_NN_RUNTIME_EXECUTION_PLAN_H #include <android-base/logging.h> +#include <nnapi/Types.h> #include <openssl/sha.h> #include <algorithm> @@ -35,7 +36,6 @@ #include <variant> #include <vector> -#include "HalInterfaces.h" #include "Memory.h" #include "ModelArgumentInfo.h" #include "ModelBuilder.h" @@ -52,8 +52,8 @@ class Device; class ExecutionBuilder; class ExecutionBurstController; class ExecutionPlan; -class Memory; -class PreparedModel; +class RuntimeMemory; +class RuntimePreparedModel; class StepExecutor; struct ConstantReferenceLocation; @@ -142,7 +142,7 @@ class DynamicTemporaries { // operand). initialDimensions and initialLength indicate what we know or // (in the case of length) guess about those properties. void declare(SourceOperandIndex sourceOperandIndex, uint32_t stepIndex, - const hal::hidl_vec<uint32_t>& initialDimensions, uint32_t initialLength); + const Dimensions& initialDimensions, uint32_t initialLength); // Indicate that we've finished declaring all dynamic temporaries. void endDeclarations() { @@ -153,8 +153,8 @@ class DynamicTemporaries { // Redeclare a dynamic temporary, indicating what we've learned about it. // This may invalidate the location of temporaries defined by its step. // Returns true if dimensions or length changed, false otherwise. - bool redeclare(SourceOperandIndex sourceOperandIndex, - const hal::hidl_vec<uint32_t>& newDimensions, uint32_t newLength); + bool redeclare(SourceOperandIndex sourceOperandIndex, const Dimensions& newDimensions, + uint32_t newLength); // Ensure that all dynamic temporaries defined by the specified step have // locations. The return value is a ResultCode (e.g., @@ -180,9 +180,9 @@ class DynamicTemporaries { // - If mustBeAllocated == true, then trigger a failed CHECK(). // - If mustBeAllocated == false, then memory == nullptr and offset == ~0. struct LocationAndShape { - const Memory* memory; + const RuntimeMemory* memory; uint32_t offset; - const hal::hidl_vec<uint32_t>* dimensions; + const Dimensions* dimensions; uint32_t length; }; std::optional<LocationAndShape> lookup(SourceOperandIndex sourceOperandIndex, @@ -197,7 +197,7 @@ class DynamicTemporaries { struct InternalLocationAndShape { uint32_t stepIndex; uint32_t offset; - hal::hidl_vec<uint32_t> dimensions; + Dimensions dimensions; uint32_t length; }; std::map<SourceOperandIndex, InternalLocationAndShape> mSourceOperandToTemporary; @@ -267,7 +267,9 @@ class ExecutionStep { std::shared_ptr<Device> getDevice() const { return mDevice; } // only available after calling finishStepModel() - std::shared_ptr<PreparedModel> getPreparedStepModel() const { return mPreparedStepModel; } + std::shared_ptr<RuntimePreparedModel> getPreparedStepModel() const { + return mPreparedStepModel; + } // Map inputs and outputs from ExecutionBuilder to StepExecutor. // @@ -278,8 +280,8 @@ class ExecutionStep { // inputs of this step are of fully specified shape. void mapInputsAndOutputs( std::shared_ptr<StepExecutor> stepExecutor, - const std::vector<hal::OutputShape>* mainModelOutputShapes, - const Memory* temporaryMemory, // for static temporaries + const std::vector<OutputShape>* mainModelOutputShapes, + const RuntimeMemory* temporaryMemory, // for static temporaries const std::map<SourceOperandIndex, uint32_t>& sourceOperandToOffsetOfTemporary, // for static temporaries const DynamicTemporaries& dynamicTemporaries, @@ -306,7 +308,7 @@ class ExecutionStep { uint32_t mSourceModelIndex; ModelBuilder mStepModel; // An excerpt of a source model to be run by one device. std::shared_ptr<Device> mDevice; - std::shared_ptr<PreparedModel> mPreparedStepModel; + std::shared_ptr<RuntimePreparedModel> mPreparedStepModel; // All inputs of this step model: // (source model operand index, step model operand index) @@ -510,9 +512,9 @@ class LogicalStep { std::variant<ExecutionStep, IfStep, WhileStep, GotoStep> mStep; }; -std::string toString(const IfStep& step); -std::string toString(const WhileStep& step); -std::string toString(const GotoStep& step); +std::ostream& operator<<(std::ostream& os, const IfStep& step); +std::ostream& operator<<(std::ostream& os, const WhileStep& step); +std::ostream& operator<<(std::ostream& os, const GotoStep& step); // Describes the state of WhileStep. struct WhileState { @@ -533,7 +535,7 @@ struct ConstantCopyLocation { }; struct ConstantReferenceLocation { - const Memory* memory; + const RuntimeMemory* memory; uint32_t offset; uint32_t length; }; @@ -660,13 +662,13 @@ class ExecutionPlan { // syncFdOfLastStep is the sync fence fd generated by the most recently processed step. int next(std::shared_ptr<Controller> controller, std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, - const std::vector<hal::OutputShape>* mainModelOutputShapes, + const std::vector<OutputShape>* mainModelOutputShapes, int syncFdOfLastStep = -1) const; // Create the same executor as the last one created by next(). int fallback(std::shared_ptr<Controller> controller, std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, - const std::vector<hal::OutputShape>* mainModelOutputShapes) const; + const std::vector<OutputShape>* mainModelOutputShapes) const; ExecutionStep* createNewExecutionStep(uint32_t sourceModelIndex, const std::shared_ptr<Device> device); @@ -737,8 +739,7 @@ class ExecutionPlan { // Illegal to call for when mState == SIMPLE. void becomeCompoundIfEmpty(); - const hal::Operand& getSourceOperand( - const std::pair<uint32_t, uint32_t>& sourceOperandIndex) const { + const Operand& getSourceOperand(const std::pair<uint32_t, uint32_t>& sourceOperandIndex) const { return getSourceModels() .getModel(sourceOperandIndex.first) ->getOperand(sourceOperandIndex.second); @@ -770,23 +771,23 @@ class ExecutionPlan { int nextCompound(std::shared_ptr<Controller> controller, std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, - const std::vector<hal::OutputShape>* mainModelOutputShapes) const; + const std::vector<OutputShape>* mainModelOutputShapes) const; int nextCompound(const ExecutionStep* step, std::shared_ptr<Controller> controller, std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, - const std::vector<hal::OutputShape>* mainModelOutputShapes) const; + const std::vector<OutputShape>* mainModelOutputShapes) const; int nextCompound(const IfStep* step, std::shared_ptr<Controller> controller, std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, - const std::vector<hal::OutputShape>* mainModelOutputShapes) const; + const std::vector<OutputShape>* mainModelOutputShapes) const; int nextCompound(const WhileStep* step, std::shared_ptr<Controller> controller, std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, - const std::vector<hal::OutputShape>* mainModelOutputShapes) const; + const std::vector<OutputShape>* mainModelOutputShapes) const; int nextCompound(const GotoStep* step, std::shared_ptr<Controller> controller, std::shared_ptr<StepExecutor>* executor, std::shared_ptr<ExecutionBurstController>* burstController, - const std::vector<hal::OutputShape>* mainModelOutputShapes) const; + const std::vector<OutputShape>* mainModelOutputShapes) const; struct Body { virtual ~Body() {} @@ -818,7 +819,7 @@ class ExecutionPlan { std::shared_ptr<Device> mDevice; const ModelBuilder* mModel; - std::shared_ptr<PreparedModel> mPreparedModel; + std::shared_ptr<RuntimePreparedModel> mPreparedModel; const std::string* mCacheDir; TokenHasher mToken; @@ -862,7 +863,8 @@ class ExecutionPlan { // to initialize ExecutionPlan::Controller::mSourceOperandToOutputIndex; std::map<SourceOperandIndex, uint32_t> mSourceOperandToOutputIndex; - // Map from source operand index to location of a CONSTANT_COPY operand. + // Map from source operand index to location of a CONSTANT_COPY or + // POINTER operand. // This map only contains constant partition boundary IF and WHILE // operands and is used to create a ExecutionPlan::Controller. std::map<SourceOperandIndex, ConstantCopyLocation> mSourceOperandToBoundaryConstantCopy; @@ -887,9 +889,9 @@ class ExecutionPlan { // values with the corresponding SUBGRAPH_INPUT operands in a referenced // model. // - // For CONSTANT_COPY boundary operands, we copy those to temporary - // memory and treat them similarly to TEMPORARY_VARIABLE operands in - // Controller. + // For CONSTANT_COPY and POINTER boundary operands, we copy those to + // temporary memory and treat them similarly to TEMPORARY_VARIABLE + // operands in Controller. // // For CONSTANT_REFERENCE boundary operands, we keep track of them in // ExecutionPlan::Controller::mSourceOperandToConstantReference. @@ -923,7 +925,7 @@ class ExecutionPlan { return static_cast<const CompoundBody*>(mBody); } - void forEachDynamicTemporary(const std::function<void(SourceOperandIndex, const hal::Operand&, + void forEachDynamicTemporary(const std::function<void(SourceOperandIndex, const Operand&, uint32_t definingStepIndex)>&) const; // Pointers to compilation caching information in CompilationBuilder. diff --git a/nn/runtime/Manager.cpp b/nn/runtime/Manager.cpp index 78d7c36a9..90d58e490 100644 --- a/nn/runtime/Manager.cpp +++ b/nn/runtime/Manager.cpp @@ -47,17 +47,13 @@ namespace android { namespace nn { -using namespace hal; - -const Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; - // A Device with actual underlying driver class DriverDevice : public Device { public: // Create a DriverDevice from a name and a DeviceFactory function. // Returns nullptr on failure. static std::shared_ptr<DriverDevice> create(const std::string& name, - const DeviceFactory& makeDevice); + const HalDeviceFactory& makeDevice); // Prefer using DriverDevice::create DriverDevice(std::shared_ptr<VersionedIDevice> device); @@ -70,25 +66,20 @@ class DriverDevice : public Device { return kInterface->getSupportedExtensions(); } std::vector<bool> getSupportedOperations(const MetaModel& metaModel) const override; - PerformanceInfo getPerformance(OperandType type) const override { - const auto& capabilities = kInterface->getCapabilities(); - return lookup(capabilities.operandPerformance, type); + Capabilities::PerformanceInfo getPerformance(OperandType type) const override { + return kInterface->getCapabilities().operandPerformance.lookup(type); } - PerformanceInfo getRelaxedFloat32toFloat16PerformanceScalar() const override { - const auto& capabilities = kInterface->getCapabilities(); - return capabilities.relaxedFloat32toFloat16PerformanceScalar; + Capabilities::PerformanceInfo getRelaxedFloat32toFloat16PerformanceScalar() const override { + return kInterface->getCapabilities().relaxedFloat32toFloat16PerformanceScalar; } - PerformanceInfo getRelaxedFloat32toFloat16PerformanceTensor() const override { - const auto& capabilities = kInterface->getCapabilities(); - return capabilities.relaxedFloat32toFloat16PerformanceTensor; + Capabilities::PerformanceInfo getRelaxedFloat32toFloat16PerformanceTensor() const override { + return kInterface->getCapabilities().relaxedFloat32toFloat16PerformanceTensor; } - PerformanceInfo getIfPerformance() const override { - const auto& capabilities = kInterface->getCapabilities(); - return capabilities.ifPerformance; + Capabilities::PerformanceInfo getIfPerformance() const override { + return kInterface->getCapabilities().ifPerformance; } - PerformanceInfo getWhilePerformance() const override { - const auto& capabilities = kInterface->getCapabilities(); - return capabilities.whilePerformance; + Capabilities::PerformanceInfo getWhilePerformance() const override { + return kInterface->getCapabilities().whilePerformance; } bool isCachingSupported() const override { // Caching is supported if either of numModelCache or numDataCache is greater than 0. @@ -98,13 +89,13 @@ class DriverDevice : public Device { } int wait() const override { return kInterface->wait(); } - std::pair<int, std::shared_ptr<PreparedModel>> prepareModel( + std::pair<int, std::shared_ptr<RuntimePreparedModel>> prepareModel( const ModelFactory& makeModel, ExecutionPreference preference, Priority priority, const std::optional<Deadline>& deadline, const std::string& cacheDir, const std::optional<CacheToken>& maybeToken) const override; - std::pair<int, std::unique_ptr<Memory>> allocate(const MemoryDescriptor& desc, - hal::OperandType) const override; + std::pair<int, std::unique_ptr<RuntimeMemory>> allocate(const MemoryDescriptor& desc, + OperandType) const override; private: const std::shared_ptr<VersionedIDevice> kInterface; @@ -117,8 +108,8 @@ class DriverDevice : public Device { #endif // NN_DEBUGGABLE }; -// A PreparedModel with underlying IPreparedModel instance return by actual driver. -class DriverPreparedModel : public PreparedModel { +// A RuntimePreparedModel with underlying IPreparedModel instance return by actual driver. +class DriverPreparedModel : public RuntimePreparedModel { public: DriverPreparedModel(const Device* device, const std::shared_ptr<VersionedIPreparedModel>& preparedModel) @@ -134,18 +125,18 @@ class DriverPreparedModel : public PreparedModel { std::tuple<int, std::vector<OutputShape>, Timing> execute( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, + const std::vector<const RuntimeMemory*>& memories, const std::shared_ptr<ExecutionBurstController>& burstController, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration) const override; - std::tuple<int, int, sp<hal::IFencedExecutionCallback>, hal::Timing> executeFenced( + std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> executeFenced( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, const std::vector<int>& waitFor, + const std::vector<const RuntimeMemory*>& memories, const std::vector<int>& waitFor, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& timeoutDurationAfterFence) const override; + const OptionalTimeoutDuration& timeoutDurationAfterFence) const override; std::shared_ptr<ExecutionBurstController> configureExecutionBurst( bool preferPowerOverLatency) const override { @@ -169,7 +160,7 @@ DriverDevice::DriverDevice(std::shared_ptr<VersionedIDevice> device) } std::shared_ptr<DriverDevice> DriverDevice::create(const std::string& name, - const DeviceFactory& makeDevice) { + const HalDeviceFactory& makeDevice) { CHECK(makeDevice != nullptr); std::shared_ptr<VersionedIDevice> device = VersionedIDevice::create(name, makeDevice); if (device == nullptr) { @@ -187,10 +178,10 @@ std::vector<bool> DriverDevice::getSupportedOperations(const MetaModel& metaMode std::vector<bool> supportedOperations; std::tie(status, supportedOperations) = kInterface->getSupportedOperations(metaModel); - const Model& hidlModel = metaModel.getModel(); - const uint32_t operationCount = hidlModel.main.operations.size(); + const Model& model = metaModel.getModel(); + const uint32_t operationCount = model.main.operations.size(); if (status != ErrorStatus::NONE) { - LOG(ERROR) << "IDevice::getSupportedOperations returned the error " << toString(status); + LOG(ERROR) << "IDevice::getSupportedOperations returned the error " << status; // Set the supported operation vectors to all false, so we won't use this driver. return std::vector<bool>(operationCount, false); } @@ -213,17 +204,18 @@ std::vector<bool> DriverDevice::getSupportedOperations(const MetaModel& metaMode } uint32_t accumulator = baseAccumulator; - const Operation& operation = hidlModel.main.operations[operationIndex]; + const Operation& operation = model.main.operations[operationIndex]; accumulator ^= static_cast<uint32_t>(operation.type); - auto accumulateOperands = [&hidlModel, &accumulator](const hidl_vec<uint32_t>& operands) { + auto accumulateOperands = [&model, &accumulator](const std::vector<uint32_t>& operands) { for (uint32_t operandIndex : operands) { - const Operand& operand = hidlModel.main.operands[operandIndex]; + const Operand& operand = model.main.operands[operandIndex]; accumulator ^= static_cast<uint32_t>(operand.type); accumulator ^= operand.dimensions.size(); - for (uint32_t dimension : operand.dimensions) { + for (const Dimension& dimension : operand.dimensions) { accumulator ^= dimension; - if (operand.lifetime == OperandLifeTime::CONSTANT_COPY || - operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE) { + if (operand.lifetime == Operand::LifeTime::CONSTANT_COPY || + operand.lifetime == Operand::LifeTime::CONSTANT_REFERENCE || + operand.lifetime == Operand::LifeTime::POINTER) { accumulator ^= 1; } } @@ -240,7 +232,7 @@ std::vector<bool> DriverDevice::getSupportedOperations(const MetaModel& metaMode return supportedOperations; } -std::pair<int, std::shared_ptr<PreparedModel>> DriverDevice::prepareModel( +std::pair<int, std::shared_ptr<RuntimePreparedModel>> DriverDevice::prepareModel( const ModelFactory& makeModel, ExecutionPreference preference, Priority priority, const std::optional<Deadline>& deadline, const std::string& cacheDir, const std::optional<CacheToken>& maybeToken) const { @@ -253,9 +245,9 @@ std::pair<int, std::shared_ptr<PreparedModel>> DriverDevice::prepareModel( return {ANEURALNETWORKS_NO_ERROR, std::make_shared<DriverPreparedModel>(this, preparedModel)}; } -std::pair<int, std::unique_ptr<Memory>> DriverDevice::allocate(const MemoryDescriptor& desc, - hal::OperandType) const { - const BufferDesc hidlDesc = {.dimensions = desc.dimensions}; +std::pair<int, std::unique_ptr<RuntimeMemory>> DriverDevice::allocate(const MemoryDescriptor& desc, + OperandType) const { + const V1_3::BufferDesc hidlDesc = {.dimensions = desc.dimensions}; std::vector<std::shared_ptr<VersionedIPreparedModel>> preparedModels( desc.preparedModels.size()); std::transform(desc.preparedModels.begin(), desc.preparedModels.end(), preparedModels.begin(), @@ -266,7 +258,7 @@ std::pair<int, std::unique_ptr<Memory>> DriverDevice::allocate(const MemoryDescr }); auto [status, buffer, token] = kInterface->allocate(hidlDesc, preparedModels, desc.inputRoles, desc.outputRoles); - if (status != ErrorStatus::NONE) { + if (status != V1_3::ErrorStatus::NONE) { LOG(ERROR) << "DriverDevice::allocate -- memory allocation on device " << getName() << " failed!"; return {convertErrorStatusToResultCode(status), nullptr}; @@ -279,7 +271,7 @@ std::pair<int, std::unique_ptr<Memory>> DriverDevice::allocate(const MemoryDescr // input a bit. static std::tuple<int, std::unique_ptr<MemoryAshmem>, std::vector<DataLocation>> allocatePointerArgumentsToPool(const std::vector<ModelArgumentInfo>& args, - std::vector<const Memory*>* memories) { + std::vector<const RuntimeMemory*>* memories) { CHECK(memories != nullptr); std::vector<DataLocation> ptrArgsLocations; const uint32_t nextPoolIndex = memories->size(); @@ -321,14 +313,14 @@ allocatePointerArgumentsToPool(const std::vector<ModelArgumentInfo>& args, // DeviceManager::mSyncExecHal. std::tuple<int, std::vector<OutputShape>, Timing> DriverPreparedModel::execute( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, + const std::vector<const RuntimeMemory*>& memories, const std::shared_ptr<ExecutionBurstController>& burstController, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration) const { NNTRACE_RT(NNTRACE_PHASE_INPUTS_AND_OUTPUTS, "DriverPreparedModel::execute"); // Make a copy of the memory tracker as we will append memory pools for pointer arguments. - std::vector<const Memory*> localMemories = memories; + std::vector<const RuntimeMemory*> localMemories = memories; // We separate the input & output pools so accelerators only need to copy // the contents of the input pools. We could also use it to set protection @@ -338,12 +330,12 @@ std::tuple<int, std::vector<OutputShape>, Timing> DriverPreparedModel::execute( const auto [n1, inputPtrArgsMemory, inputPtrArgsLocations] = allocatePointerArgumentsToPool(inputs, &localMemories); if (n1 != ANEURALNETWORKS_NO_ERROR) { - return {n1, {}, kNoTiming}; + return {n1, {}, {}}; } const auto [n2, outputPtrArgsMemory, outputPtrArgsLocations] = allocatePointerArgumentsToPool(outputs, &localMemories); if (n2 != ANEURALNETWORKS_NO_ERROR) { - return {n2, {}, kNoTiming}; + return {n2, {}, {}}; } // Copy the input data that was specified via a pointer. @@ -364,7 +356,7 @@ std::tuple<int, std::vector<OutputShape>, Timing> DriverPreparedModel::execute( uint32_t count = localMemories.size(); request.pools.resize(count); for (uint32_t i = 0; i < count; i++) { - request.pools[i] = localMemories[i]->getMemoryPool(); + request.pools[i] = uncheckedConvert(localMemories[i]->getMemoryPool()); } NNTRACE_FULL_SWITCH(NNTRACE_LAYER_IPC, NNTRACE_PHASE_EXECUTION, @@ -372,26 +364,30 @@ std::tuple<int, std::vector<OutputShape>, Timing> DriverPreparedModel::execute( int n = ANEURALNETWORKS_OP_FAILED; std::vector<OutputShape> outputShapes; - Timing timing = kNoTiming; + Timing timing; // compute using burst if present const bool burstCompute = (burstController != nullptr); bool burstFallback = true; if (burstCompute) { - const bool compliant = compliantWithV1_2(request); + const bool compliant = compliantWithV1_2(convertToV1_3(request)); if (compliant) { - V1_0::Request request12 = convertToV1_2(request); + V1_0::Request request12 = convertToV1_2(convertToV1_3(request)); std::vector<intptr_t> memoryIds; memoryIds.reserve(localMemories.size()); - for (const Memory* memory : localMemories) { + for (const RuntimeMemory* memory : localMemories) { memory->usedBy(burstController); memoryIds.push_back(memory->getKey()); } VLOG(EXECUTION) << "Before ExecutionBurstController->compute() " << SHOW_IF_DEBUG(toString(request12)); - std::tie(n, outputShapes, timing, burstFallback) = - burstController->compute(request12, measure, memoryIds); + std::vector<V1_2::OutputShape> halOutputShapes; + V1_2::Timing halTiming; + std::tie(n, halOutputShapes, halTiming, burstFallback) = + burstController->compute(request12, convertToV1_2(measure), memoryIds); + outputShapes = uncheckedConvert(halOutputShapes); + timing = uncheckedConvert(halTiming); } } @@ -426,19 +422,18 @@ std::tuple<int, std::vector<OutputShape>, Timing> DriverPreparedModel::execute( return {ANEURALNETWORKS_NO_ERROR, std::move(outputShapes), timing}; } -std::tuple<int, int, sp<hal::IFencedExecutionCallback>, hal::Timing> -DriverPreparedModel::executeFenced( +std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedModel::executeFenced( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, const std::vector<int>& waitFor, - hal::MeasureTiming measure, const std::optional<Deadline>& deadline, + const std::vector<const RuntimeMemory*>& memories, const std::vector<int>& waitFor, + MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& timeoutDurationAfterFence) const { + const OptionalTimeoutDuration& timeoutDurationAfterFence) const { NNTRACE_RT(NNTRACE_PHASE_INPUTS_AND_OUTPUTS, "DriverPreparedModel::executeFenced"); CHECK(std::all_of(waitFor.begin(), waitFor.end(), [](int fd) { return fd > 0; })); // Make a copy of the memory tracker as we will append memory pools for pointer arguments. - std::vector<const Memory*> localMemories = memories; - sp<hal::IFencedExecutionCallback> executeFencedCallback; - hal::Timing timing = kNoTiming; + std::vector<const RuntimeMemory*> localMemories = memories; + sp<V1_3::IFencedExecutionCallback> executeFencedCallback; + Timing timing; // We separate the input & output pools so accelerators only need to copy // the contents of the input pools. We could also use it to set protection @@ -474,14 +469,14 @@ DriverPreparedModel::executeFenced( uint32_t count = localMemories.size(); request.pools.resize(count); for (uint32_t i = 0; i < count; i++) { - request.pools[i] = localMemories[i]->getMemoryPool(); + request.pools[i] = uncheckedConvert(localMemories[i]->getMemoryPool()); } NNTRACE_FULL_SWITCH(NNTRACE_LAYER_IPC, NNTRACE_PHASE_EXECUTION, "DriverPreparedModel::executeFenced"); int n = ANEURALNETWORKS_OP_FAILED; - hidl_vec<hidl_handle> waitForHandles; + hardware::hidl_vec<hardware::hidl_handle> waitForHandles; waitForHandles.resize(waitFor.size()); for (uint32_t i = 0; i < waitFor.size(); i++) { native_handle_t* nativeHandle = native_handle_create(1, 0); @@ -495,12 +490,12 @@ DriverPreparedModel::executeFenced( return {n, -1, nullptr, timing}; } nativeHandle->data[0] = dupFd; - hidl_handle hidlHandle; + hardware::hidl_handle hidlHandle; hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true); waitForHandles[i] = std::move(hidlHandle); } - hidl_handle syncFence; + hardware::hidl_handle syncFence; std::tie(n, syncFence, executeFencedCallback, timing) = mPreparedModel->executeFenced(request, waitForHandles, measure, deadline, loopTimeoutDuration, timeoutDurationAfterFence); @@ -561,25 +556,27 @@ class CpuDevice : public Device { return kSupportedExtensions; } std::vector<bool> getSupportedOperations(const MetaModel& metaModel) const override; - PerformanceInfo getPerformance(OperandType) const override { return kPerformance; } - PerformanceInfo getRelaxedFloat32toFloat16PerformanceScalar() const override { + Capabilities::PerformanceInfo getPerformance(OperandType) const override { return kPerformance; } - PerformanceInfo getRelaxedFloat32toFloat16PerformanceTensor() const override { + Capabilities::PerformanceInfo getRelaxedFloat32toFloat16PerformanceScalar() const override { return kPerformance; } - PerformanceInfo getIfPerformance() const override { return kPerformance; } - PerformanceInfo getWhilePerformance() const override { return kPerformance; } + Capabilities::PerformanceInfo getRelaxedFloat32toFloat16PerformanceTensor() const override { + return kPerformance; + } + Capabilities::PerformanceInfo getIfPerformance() const override { return kPerformance; } + Capabilities::PerformanceInfo getWhilePerformance() const override { return kPerformance; } bool isCachingSupported() const override { return false; } int wait() const override { return ANEURALNETWORKS_NO_ERROR; } - std::pair<int, std::shared_ptr<PreparedModel>> prepareModel( + std::pair<int, std::shared_ptr<RuntimePreparedModel>> prepareModel( const ModelFactory& makeModel, ExecutionPreference preference, Priority priority, const std::optional<Deadline>& deadline, const std::string& cacheDir, const std::optional<CacheToken>& maybeToken) const override; - std::pair<int, std::unique_ptr<Memory>> allocate(const MemoryDescriptor& desc, - OperandType type) const override; + std::pair<int, std::unique_ptr<RuntimeMemory>> allocate(const MemoryDescriptor& desc, + OperandType type) const override; private: CpuDevice() = default; @@ -588,17 +585,17 @@ class CpuDevice : public Device { const std::string kVersionString = build::GetBuildNumber(); // Since the performance is a ratio compared to the CPU performance, // by definition the performance of the CPU is 1.0. - const PerformanceInfo kPerformance = {.execTime = 1.0f, .powerUsage = 1.0f}; + const Capabilities::PerformanceInfo kPerformance = {.execTime = 1.0f, .powerUsage = 1.0f}; const std::vector<Extension> kSupportedExtensions{/* No extensions. */}; }; -// A special abstracted PreparedModel for the CPU, constructed by CpuDevice. -class CpuPreparedModel : public PreparedModel { +// A special abstracted RuntimePreparedModel for the CPU, constructed by CpuDevice. +class CpuPreparedModel : public RuntimePreparedModel { public: // Factory method for CpuPreparedModel. Returns ANEURALNETWORKS_NO_ERROR and // a prepared model object if successfully created. Returns an error code // and nullptr otherwise. - static std::pair<int, std::shared_ptr<PreparedModel>> create(Model hidlModel); + static std::pair<int, std::shared_ptr<RuntimePreparedModel>> create(Model model); const Device* getDevice() const override { return CpuDevice::get().get(); } std::shared_ptr<VersionedIPreparedModel> getInterface() const override { return nullptr; } @@ -606,7 +603,7 @@ class CpuPreparedModel : public PreparedModel { std::tuple<int, std::vector<OutputShape>, Timing> execute( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, + const std::vector<const RuntimeMemory*>& memories, const std::shared_ptr<ExecutionBurstController>& burstController, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration) const override; @@ -616,13 +613,13 @@ class CpuPreparedModel : public PreparedModel { return nullptr; } - std::tuple<int, int, sp<hal::IFencedExecutionCallback>, hal::Timing> executeFenced( + std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> executeFenced( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, const std::vector<int>& wait_for, + const std::vector<const RuntimeMemory*>& memories, const std::vector<int>& wait_for, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& timeoutDurationAfterFence) const override; + const OptionalTimeoutDuration& timeoutDurationAfterFence) const override; // Prefer to use CpuPreparedModel::create. CpuPreparedModel(Model model, std::vector<RunTimePoolInfo> poolInfos) @@ -634,21 +631,20 @@ class CpuPreparedModel : public PreparedModel { }; std::vector<bool> CpuDevice::getSupportedOperations(const MetaModel& metaModel) const { - const Model& hidlModel = metaModel.getModel(); - const size_t count = hidlModel.main.operations.size(); + const Model& model = metaModel.getModel(); + const size_t count = model.main.operations.size(); std::vector<bool> result(count, false); for (size_t i = 0; i < count; i++) { // TODO(b/119870033): Decide whether and how post-P operations would be supported on CPU. // We may want to use the slicer for CpuDevice just as we do for // DriverDevice. - OperationType operationType = hidlModel.main.operations[i].type; - result[i] = !isExtensionOperationType(operationType) && - operationType != OperationType::OEM_OPERATION; + OperationType operationType = model.main.operations[i].type; + result[i] = !isExtension(operationType) && operationType != OperationType::OEM_OPERATION; } return result; } -std::pair<int, std::shared_ptr<PreparedModel>> CpuDevice::prepareModel( +std::pair<int, std::shared_ptr<RuntimePreparedModel>> CpuDevice::prepareModel( const ModelFactory& makeModel, ExecutionPreference preference, Priority priority, const std::optional<Deadline>& deadline, const std::string& /*cacheDir*/, const std::optional<CacheToken>& maybeToken) const { @@ -656,8 +652,9 @@ std::pair<int, std::shared_ptr<PreparedModel>> CpuDevice::prepareModel( << "Should never call prepareModel with cache information on CpuDevice"; const Model model = makeModel(); - if (!validateModel(model, ValidationMode::RUNTIME) || - !validateExecutionPreference(preference) || !validatePriority(priority)) { + if (!validateModel(convertToV1_3(model), ValidationMode::RUNTIME) || + !validateExecutionPreference(convertToV1_1(preference)) || + !validatePriority(convertToV1_3(priority))) { return {ANEURALNETWORKS_OP_FAILED, nullptr}; } if (hasDeadlinePassed(deadline)) { @@ -667,8 +664,8 @@ std::pair<int, std::shared_ptr<PreparedModel>> CpuDevice::prepareModel( return CpuPreparedModel::create(model); } -std::pair<int, std::unique_ptr<Memory>> CpuDevice::allocate(const MemoryDescriptor& desc, - OperandType type) const { +std::pair<int, std::unique_ptr<RuntimeMemory>> CpuDevice::allocate(const MemoryDescriptor& desc, + OperandType type) const { uint32_t size = TypeManager::get()->getSizeOfData(type, desc.dimensions); if (size == 0) { LOG(ERROR) << "CpuDevice::allocate -- does not support unknown dimensions."; @@ -677,14 +674,14 @@ std::pair<int, std::unique_ptr<Memory>> CpuDevice::allocate(const MemoryDescript return MemoryAshmem::create(size); } -std::pair<int, std::shared_ptr<PreparedModel>> CpuPreparedModel::create(Model hidlModel) { +std::pair<int, std::shared_ptr<RuntimePreparedModel>> CpuPreparedModel::create(Model model) { std::vector<RunTimePoolInfo> poolInfos; - if (!setRunTimePoolInfosFromHidlMemories(&poolInfos, hidlModel.pools)) { + if (!setRunTimePoolInfosFromCanonicalMemories(&poolInfos, model.pools)) { return {ANEURALNETWORKS_UNMAPPABLE, nullptr}; } - std::shared_ptr<PreparedModel> preparedModel = - std::make_shared<CpuPreparedModel>(std::move(hidlModel), std::move(poolInfos)); + std::shared_ptr<RuntimePreparedModel> preparedModel = + std::make_shared<CpuPreparedModel>(std::move(model), std::move(poolInfos)); return {ANEURALNETWORKS_NO_ERROR, std::move(preparedModel)}; } @@ -696,26 +693,23 @@ static std::tuple<int, std::vector<OutputShape>, Timing> computeOnCpu( const OptionalTimeoutDuration& loopTimeoutDuration) { NNTRACE_RT(NNTRACE_PHASE_EXECUTION, "computeOnCpu"); CpuExecutor executor; - if (loopTimeoutDuration.getDiscriminator() != - OptionalTimeoutDuration::hidl_discriminator::none) { - executor.setLoopTimeout(loopTimeoutDuration.nanoseconds()); + if (loopTimeoutDuration.has_value()) { + executor.setLoopTimeout(loopTimeoutDuration->count()); } if (deadline.has_value()) { executor.setDeadline(*deadline); } int err = executor.run(model, request, modelPoolInfos, requestPoolInfos); const auto& outputShapes = executor.getOutputShapes(); - return {err, outputShapes, kNoTiming}; + return {err, outputShapes, {}}; } -std::tuple<int, int, sp<hal::IFencedExecutionCallback>, hal::Timing> -CpuPreparedModel::executeFenced(const std::vector<ModelArgumentInfo>& inputs, - const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, - const std::vector<int>& waitFor, hal::MeasureTiming measure, - const std::optional<Deadline>& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& duration) const { +std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> CpuPreparedModel::executeFenced( + const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, + const std::vector<const RuntimeMemory*>& memories, const std::vector<int>& waitFor, + MeasureTiming measure, const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + const OptionalTimeoutDuration& duration) const { VLOG(EXECUTION) << "CpuPreparedModel::executeFenced wait for sync fences to signal before execution"; for (int syncFd : waitFor) { @@ -730,8 +724,8 @@ CpuPreparedModel::executeFenced(const std::vector<ModelArgumentInfo>& inputs, // Update deadline if the timeout duration is closer than the deadline. auto closestDeadline = deadline; - if (duration.getDiscriminator() != OptionalTimeoutDuration::hidl_discriminator::none) { - const auto timeoutDurationDeadline = makeDeadline(duration.nanoseconds()); + if (duration.has_value()) { + const auto timeoutDurationDeadline = makeDeadline(*duration); if (!closestDeadline.has_value() || *closestDeadline > timeoutDurationDeadline) { closestDeadline = timeoutDurationDeadline; } @@ -751,21 +745,21 @@ CpuPreparedModel::executeFenced(const std::vector<ModelArgumentInfo>& inputs, // Will choose between sync/async execution according to DeviceManager::mSyncExecCpu. std::tuple<int, std::vector<OutputShape>, Timing> CpuPreparedModel::execute( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, + const std::vector<const RuntimeMemory*>& memories, const std::shared_ptr<ExecutionBurstController>& /*burstController*/, MeasureTiming /*measure*/, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration) const { if (hasDeadlinePassed(deadline)) { - return {ANEURALNETWORKS_MISSED_DEADLINE_PERSISTENT, {}, kNoTiming}; + return {ANEURALNETWORKS_MISSED_DEADLINE_PERSISTENT, {}, {}}; } std::vector<RunTimePoolInfo> requestPoolInfos; requestPoolInfos.reserve(memories.size()); - for (const Memory* mem : memories) { + for (const RuntimeMemory* mem : memories) { if (std::optional<RunTimePoolInfo> poolInfo = mem->getRunTimePoolInfo()) { requestPoolInfos.emplace_back(*poolInfo); } else { - return {ANEURALNETWORKS_UNMAPPABLE, {}, kNoTiming}; + return {ANEURALNETWORKS_UNMAPPABLE, {}, {}}; } } // Create as many pools as there are input / output. @@ -818,7 +812,7 @@ std::shared_ptr<Device> DeviceManager::getCpuDevice() { std::shared_ptr<Device> DeviceManager::forTest_makeDriverDevice(const std::string& name, const sp<V1_0::IDevice>& device) { - const DeviceFactory makeDevice = [device](bool /*blocking*/) { return device; }; + const HalDeviceFactory makeDevice = [device](bool /*blocking*/) { return device; }; const auto driverDevice = DriverDevice::create(name, makeDevice); CHECK(driverDevice != nullptr); return driverDevice; @@ -831,7 +825,7 @@ void DeviceManager::findAvailableDevices() { const auto names = hardware::getAllHalInstanceNames(V1_0::IDevice::descriptor); for (const auto& name : names) { VLOG(MANAGER) << "Found interface " << name; - const DeviceFactory makeDevice = [name](bool blocking) { + const HalDeviceFactory makeDevice = [name](bool blocking) { return blocking ? V1_0::IDevice::getService(name) : V1_0::IDevice::tryGetService(name); }; registerDevice(name, makeDevice); @@ -842,7 +836,7 @@ void DeviceManager::findAvailableDevices() { mDevicesCpuOnly.push_back(CpuDevice::get()); } -void DeviceManager::registerDevice(const std::string& name, const DeviceFactory& makeDevice) { +void DeviceManager::registerDevice(const std::string& name, const HalDeviceFactory& makeDevice) { if (auto device = DriverDevice::create(name, makeDevice)) { mDevices.push_back(std::move(device)); } diff --git a/nn/runtime/Manager.h b/nn/runtime/Manager.h index d6d483576..3e3ce033f 100644 --- a/nn/runtime/Manager.h +++ b/nn/runtime/Manager.h @@ -43,40 +43,42 @@ class ModelArgumentInfo; class VersionedIPreparedModel; // A unified interface for actual driver prepared model as well as the CPU. -class PreparedModel { - DISALLOW_COPY_AND_ASSIGN(PreparedModel); +class RuntimePreparedModel { + DISALLOW_COPY_AND_ASSIGN(RuntimePreparedModel); public: - PreparedModel() = default; - virtual ~PreparedModel() = default; + RuntimePreparedModel() = default; + virtual ~RuntimePreparedModel() = default; virtual const Device* getDevice() const = 0; virtual std::shared_ptr<VersionedIPreparedModel> getInterface() const = 0; // Perform computation with given input/output argument info and memory pools. - virtual std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> execute( + virtual std::tuple<int, std::vector<OutputShape>, Timing> execute( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, - const std::shared_ptr<ExecutionBurstController>& burstController, - hal::MeasureTiming measure, const std::optional<Deadline>& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration) const = 0; + const std::vector<const RuntimeMemory*>& memories, + const std::shared_ptr<ExecutionBurstController>& burstController, MeasureTiming measure, + const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration) const = 0; // Perform fenced computation with given input/output argument info and memory pools. // The returned timing information is only valid if the callback is nullptr. // Returns error_code, sync_fence, callback and timing. - virtual std::tuple<int, int, sp<hal::IFencedExecutionCallback>, hal::Timing> executeFenced( + virtual std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> executeFenced( const std::vector<ModelArgumentInfo>& inputs, const std::vector<ModelArgumentInfo>& outputs, - const std::vector<const Memory*>& memories, const std::vector<int>& waitFor, - hal::MeasureTiming measure, const std::optional<Deadline>& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& timeoutDurationAfterFence) const = 0; + const std::vector<const RuntimeMemory*>& memories, const std::vector<int>& waitFor, + MeasureTiming measure, const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + const OptionalTimeoutDuration& timeoutDurationAfterFence) const = 0; virtual std::shared_ptr<ExecutionBurstController> configureExecutionBurst( bool preferPowerOverLatency) const = 0; }; +using ModelFactory = std::function<Model()>; + // A unified interface for actual driver devices as well as the CPU class Device { DISALLOW_COPY_AND_ASSIGN(Device); @@ -90,29 +92,28 @@ class Device { virtual const std::string& getVersionString() const = 0; virtual int64_t getFeatureLevel() const = 0; virtual int32_t getType() const = 0; - virtual const std::vector<hal::Extension>& getSupportedExtensions() const = 0; + virtual const std::vector<Extension>& getSupportedExtensions() const = 0; // See the MetaModel class in MetaModel.h for more details. virtual std::vector<bool> getSupportedOperations(const MetaModel& metaModel) const = 0; - virtual hal::PerformanceInfo getPerformance(hal::OperandType type) const = 0; - virtual hal::PerformanceInfo getRelaxedFloat32toFloat16PerformanceScalar() const = 0; - virtual hal::PerformanceInfo getRelaxedFloat32toFloat16PerformanceTensor() const = 0; - virtual hal::PerformanceInfo getIfPerformance() const = 0; - virtual hal::PerformanceInfo getWhilePerformance() const = 0; + virtual Capabilities::PerformanceInfo getPerformance(OperandType type) const = 0; + virtual Capabilities::PerformanceInfo getRelaxedFloat32toFloat16PerformanceScalar() const = 0; + virtual Capabilities::PerformanceInfo getRelaxedFloat32toFloat16PerformanceTensor() const = 0; + virtual Capabilities::PerformanceInfo getIfPerformance() const = 0; + virtual Capabilities::PerformanceInfo getWhilePerformance() const = 0; virtual bool isCachingSupported() const = 0; virtual int wait() const = 0; - virtual std::pair<int, std::shared_ptr<PreparedModel>> prepareModel( - const hal::ModelFactory& makeModel, hal::ExecutionPreference preference, - hal::Priority priority, const std::optional<Deadline>& deadline, - const std::string& cacheDir, - const std::optional<hal::CacheToken>& maybeToken) const = 0; + virtual std::pair<int, std::shared_ptr<RuntimePreparedModel>> prepareModel( + const ModelFactory& makeModel, ExecutionPreference preference, Priority priority, + const std::optional<Deadline>& deadline, const std::string& cacheDir, + const std::optional<CacheToken>& maybeToken) const = 0; - // The caller is responsible for making sure the MemoryDescriptor only contains PreparedModels - // from the same Device. - virtual std::pair<int, std::unique_ptr<Memory>> allocate(const MemoryDescriptor& desc, - hal::OperandType type) const = 0; + // The caller is responsible for making sure the MemoryDescriptor only contains + // PreparedModels from the same Device. + virtual std::pair<int, std::unique_ptr<RuntimeMemory>> allocate(const MemoryDescriptor& desc, + OperandType type) const = 0; }; // Manages the NN HAL devices. Only one instance of this class will exist. @@ -168,8 +169,8 @@ class DeviceManager { } // Register a test device. - void forTest_registerDevice(const std::string& name, const sp<hal::V1_0::IDevice>& device) { - const hal::DeviceFactory makeDevice = [device](bool /*blocking*/) { return device; }; + void forTest_registerDevice(const std::string& name, const sp<V1_0::IDevice>& device) { + const HalDeviceFactory makeDevice = [device](bool /*blocking*/) { return device; }; registerDevice(name, makeDevice); } @@ -182,7 +183,7 @@ class DeviceManager { // Make a test device static std::shared_ptr<Device> forTest_makeDriverDevice(const std::string& name, - const sp<hal::V1_0::IDevice>& device); + const sp<V1_0::IDevice>& device); bool forTest_isCpuDevice(const ANeuralNetworksDevice* device) const { return reinterpret_cast<const Device*>(device) == getCpuDevice().get(); @@ -193,7 +194,7 @@ class DeviceManager { DeviceManager(); // Adds a device for the manager to use. - void registerDevice(const std::string& name, const hal::DeviceFactory& makeDevice); + void registerDevice(const std::string& name, const HalDeviceFactory& makeDevice); void findAvailableDevices(); diff --git a/nn/runtime/Memory.cpp b/nn/runtime/Memory.cpp index ee9faf934..7efaf643b 100644 --- a/nn/runtime/Memory.cpp +++ b/nn/runtime/Memory.cpp @@ -30,6 +30,8 @@ #include <utility> #include <vector> +#include <nnapi/TypeUtils.h> +#include <nnapi/Types.h> #include "CompilationBuilder.h" #include "CpuExecutor.h" #include "ExecutionBurstController.h" @@ -41,7 +43,7 @@ namespace android { namespace nn { -using namespace hal; +using ::android::hidl::memory::V1_0::IMemory; namespace { @@ -183,17 +185,18 @@ class DeviceMemoryValidator : public MemoryValidatorBase { } // namespace -Memory::Memory(hal::hidl_memory memory) +RuntimeMemory::RuntimeMemory(hardware::hidl_memory memory) : kHidlMemory(std::move(memory)), mValidator(std::make_unique<SizedMemoryValidator>(kHidlMemory.size())) {} -Memory::Memory(hal::hidl_memory memory, std::unique_ptr<MemoryValidatorBase> validator) +RuntimeMemory::RuntimeMemory(hardware::hidl_memory memory, + std::unique_ptr<MemoryValidatorBase> validator) : kHidlMemory(std::move(memory)), mValidator(std::move(validator)) {} -Memory::Memory(sp<hal::IBuffer> buffer, uint32_t token) +RuntimeMemory::RuntimeMemory(sp<V1_3::IBuffer> buffer, uint32_t token) : kBuffer(std::move(buffer)), kToken(token) {} -Memory::~Memory() { +RuntimeMemory::~RuntimeMemory() { for (const auto& [ptr, weakBurst] : mUsedBy) { if (const std::shared_ptr<ExecutionBurstController> burst = weakBurst.lock()) { burst->freeMemory(getKey()); @@ -201,8 +204,8 @@ Memory::~Memory() { } } -Request::MemoryPool Memory::getMemoryPool() const { - Request::MemoryPool pool; +V1_3::Request::MemoryPool RuntimeMemory::getMemoryPool() const { + V1_3::Request::MemoryPool pool; if (kToken > 0) { pool.token(kToken); } else { @@ -211,20 +214,20 @@ Request::MemoryPool Memory::getMemoryPool() const { return pool; } -std::optional<RunTimePoolInfo> Memory::getRunTimePoolInfo() const { +std::optional<RunTimePoolInfo> RuntimeMemory::getRunTimePoolInfo() const { std::lock_guard<std::mutex> guard(mMutex); if (!mHasCachedRunTimePoolInfo) { - mCachedRunTimePoolInfo = RunTimePoolInfo::createFromHidlMemory(kHidlMemory); + mCachedRunTimePoolInfo = RunTimePoolInfo::createFromMemory(uncheckedConvert(kHidlMemory)); mHasCachedRunTimePoolInfo = true; } return mCachedRunTimePoolInfo; } -intptr_t Memory::getKey() const { +intptr_t RuntimeMemory::getKey() const { return reinterpret_cast<intptr_t>(this); } -void Memory::usedBy(const std::shared_ptr<ExecutionBurstController>& burst) const { +void RuntimeMemory::usedBy(const std::shared_ptr<ExecutionBurstController>& burst) const { std::lock_guard<std::mutex> guard(mMutex); mUsedBy.emplace(burst.get(), burst); } @@ -246,37 +249,37 @@ static int copyHidlMemories(const std::optional<RunTimePoolInfo>& src, return ANEURALNETWORKS_NO_ERROR; } -int copyIBufferToHidlMemory(const sp<IBuffer>& src, const hidl_memory& dst) { +int copyIBufferToHidlMemory(const sp<V1_3::IBuffer>& src, const hardware::hidl_memory& dst) { const auto ret = src->copyTo(dst); if (!ret.isOk()) { LOG(ERROR) << "ANeuralNetworksMemory_copy failure: " << ret.description(); return ANEURALNETWORKS_OP_FAILED; } - return convertErrorStatusToResultCode(static_cast<ErrorStatus>(ret)); + return convertErrorStatusToResultCode(static_cast<V1_3::ErrorStatus>(ret)); } -int copyHidlMemoryToIBuffer(const hidl_memory& src, const sp<IBuffer>& dst, +int copyHidlMemoryToIBuffer(const hardware::hidl_memory& src, const sp<V1_3::IBuffer>& dst, const std::vector<uint32_t>& dimensions) { const auto ret = dst->copyFrom(src, dimensions); if (!ret.isOk()) { LOG(ERROR) << "ANeuralNetworksMemory_copy failure: " << ret.description(); return ANEURALNETWORKS_OP_FAILED; } - return convertErrorStatusToResultCode(static_cast<ErrorStatus>(ret)); + return convertErrorStatusToResultCode(static_cast<V1_3::ErrorStatus>(ret)); } -static int copyIBuffers(const sp<IBuffer>& src, const sp<IBuffer>& dst, +static int copyIBuffers(const sp<V1_3::IBuffer>& src, const sp<V1_3::IBuffer>& dst, const MemoryValidatorBase::Metadata& srcMetadata) { const auto [n, memory] = MemoryRuntimeAHWB::create(srcMetadata.logicalSize); NN_RETURN_IF_ERROR(n); - const hidl_memory& hidlMemory = memory->getHidlMemory(); + const hardware::hidl_memory& hidlMemory = memory->getHidlMemory(); if (!hidlMemory.valid()) return ANEURALNETWORKS_OUT_OF_MEMORY; NN_RETURN_IF_ERROR(copyIBufferToHidlMemory(src, hidlMemory)); NN_RETURN_IF_ERROR(copyHidlMemoryToIBuffer(hidlMemory, dst, srcMetadata.dimensions)); return ANEURALNETWORKS_NO_ERROR; } -static int copyInternal(const Memory& src, const Memory& dst) { +static int copyInternal(const RuntimeMemory& src, const RuntimeMemory& dst) { if (&src == &dst) return ANEURALNETWORKS_NO_ERROR; if (!src.getValidator().isInitialized()) { @@ -307,7 +310,7 @@ static int copyInternal(const Memory& src, const Memory& dst) { return ANEURALNETWORKS_OP_FAILED; } -int Memory::copy(const Memory& src, const Memory& dst) { +int RuntimeMemory::copy(const RuntimeMemory& src, const RuntimeMemory& dst) { int n = copyInternal(src, dst); dst.getValidator().setInitialized(n == ANEURALNETWORKS_NO_ERROR); return n; @@ -333,7 +336,7 @@ int MemoryBuilder::addRole(const CompilationBuilder& compilation, IOType ioType, return ANEURALNETWORKS_BAD_DATA; } - std::vector<std::tuple<const PreparedModel*, IOType, uint32_t>> roles; + std::vector<std::tuple<const RuntimePreparedModel*, IOType, uint32_t>> roles; auto callback = [&roles](const auto* preparedModel, IOType type, uint32_t index) { roles.emplace_back(preparedModel, type, index); }; @@ -421,10 +424,10 @@ int MemoryBuilder::setDimensions(const std::vector<uint32_t>& dimensions) { static void logMemoryDescriptorToInfo(const MemoryDescriptor& desc, const Operand& operand) { LOG(INFO) << "MemoryDescriptor start"; - LOG(INFO) << " Data type: " << toString(operand.type); - LOG(INFO) << " Scale: " << toString(operand.scale); - LOG(INFO) << " Zero point: " << toString(operand.zeroPoint); - LOG(INFO) << " Extra params: " << toString(operand.extraParams); + LOG(INFO) << " Data type: " << operand.type; + LOG(INFO) << " Scale: " << operand.scale; + LOG(INFO) << " Zero point: " << operand.zeroPoint; + LOG(INFO) << " Extra params: " << operand.extraParams; LOG(INFO) << " Dimensions: " << toString(desc.dimensions); LOG(INFO) << " Prepared models [" << desc.preparedModels.size() << "]:"; for (const auto* preparedModel : desc.preparedModels) { @@ -432,11 +435,11 @@ static void logMemoryDescriptorToInfo(const MemoryDescriptor& desc, const Operan } LOG(INFO) << " Input roles [" << desc.inputRoles.size() << "]:"; for (const auto& usage : desc.inputRoles) { - LOG(INFO) << " " << toString(usage); + LOG(INFO) << " " << usage; } LOG(INFO) << " Output roles [" << desc.outputRoles.size() << "]:"; for (const auto& usage : desc.outputRoles) { - LOG(INFO) << " " << toString(usage); + LOG(INFO) << " " << usage; } LOG(INFO) << "MemoryDescriptor end"; } @@ -484,14 +487,14 @@ int MemoryBuilder::finish() { return ANEURALNETWORKS_NO_ERROR; } -std::pair<int, std::unique_ptr<Memory>> MemoryBuilder::allocate() const { +std::pair<int, std::unique_ptr<RuntimeMemory>> MemoryBuilder::allocate() const { if (!mFinished) { LOG(ERROR) << "ANeuralNetworksMemory_createFromDesc -- passed an unfinished descriptor"; return {ANEURALNETWORKS_BAD_STATE, nullptr}; } int n = ANEURALNETWORKS_OP_FAILED; - std::unique_ptr<Memory> memory; + std::unique_ptr<RuntimeMemory> memory; CHECK(mOperand.has_value()); // Try allocate the memory on device. @@ -521,10 +524,10 @@ std::pair<int, std::unique_ptr<Memory>> MemoryBuilder::allocate() const { } std::pair<int, std::unique_ptr<MemoryAshmem>> MemoryAshmem::create(uint32_t size) { - hidl_memory hidlMemory = allocateSharedMemory(size); + hardware::hidl_memory hidlMemory = allocateSharedMemory(size); sp<IMemory> mapped = mapMemory(hidlMemory); if (mapped == nullptr || mapped->getPointer() == nullptr) { - LOG(ERROR) << "Memory::create failed"; + LOG(ERROR) << "RuntimeMemory::create failed"; return {ANEURALNETWORKS_OUT_OF_MEMORY, nullptr}; } return {ANEURALNETWORKS_NO_ERROR, @@ -535,8 +538,8 @@ uint8_t* MemoryAshmem::getPointer() const { return static_cast<uint8_t*>(static_cast<void*>(kMappedMemory->getPointer())); } -MemoryAshmem::MemoryAshmem(sp<IMemory> mapped, hidl_memory memory) - : Memory(std::move(memory)), kMappedMemory(std::move(mapped)) {} +MemoryAshmem::MemoryAshmem(sp<IMemory> mapped, hardware::hidl_memory memory) + : RuntimeMemory(std::move(memory)), kMappedMemory(std::move(mapped)) {} std::pair<int, std::unique_ptr<MemoryFd>> MemoryFd::create(size_t size, int prot, int fd, size_t offset) { @@ -576,25 +579,26 @@ std::pair<int, std::unique_ptr<MemoryFd>> MemoryFd::create(size_t size, int prot // Push the hidl_handle into a hidl_memory object. The hidl_memory object is // responsible for cleaning the hidl_handle, the native handle, and the fd. - hidl_memory hidlMemory = hidl_memory("mmap_fd", std::move(hidlHandle), size); + hardware::hidl_memory hidlMemory = + hardware::hidl_memory("mmap_fd", std::move(hidlHandle), size); return {ANEURALNETWORKS_NO_ERROR, std::make_unique<MemoryFd>(std::move(hidlMemory))}; } -MemoryFd::MemoryFd(hidl_memory memory) : Memory(std::move(memory)) {} +MemoryFd::MemoryFd(hardware::hidl_memory memory) : RuntimeMemory(std::move(memory)) {} std::pair<int, std::unique_ptr<MemoryAHWB>> MemoryAHWB::create(const AHardwareBuffer& ahwb) { AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_describe(&ahwb, &bufferDesc); const native_handle_t* handle = AHardwareBuffer_getNativeHandle(&ahwb); - hidl_memory hidlMemory; + hardware::hidl_memory hidlMemory; std::unique_ptr<MemoryValidatorBase> validator; if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) { - hidlMemory = hidl_memory("hardware_buffer_blob", handle, bufferDesc.width); + hidlMemory = hardware::hidl_memory("hardware_buffer_blob", handle, bufferDesc.width); validator = std::make_unique<SizedMemoryValidator>(bufferDesc.width); } else { // memory size is not used. - hidlMemory = hidl_memory("hardware_buffer", handle, 0); + hidlMemory = hardware::hidl_memory("hardware_buffer", handle, 0); validator = std::make_unique<AHardwareBufferNonBlobValidator>(); } auto memory = std::make_unique<MemoryAHWB>(std::move(hidlMemory), std::move(validator)); @@ -633,7 +637,8 @@ std::pair<int, std::unique_ptr<MemoryRuntimeAHWB>> MemoryRuntimeAHWB::create(uin return {ANEURALNETWORKS_OP_FAILED, nullptr}; } - hidl_memory hidlMemory = hidl_memory("hardware_buffer_blob", handle, desc.width); + hardware::hidl_memory hidlMemory = + hardware::hidl_memory("hardware_buffer_blob", handle, desc.width); auto memory = std::make_unique<MemoryRuntimeAHWB>(std::move(hidlMemory), ahwb, static_cast<uint8_t*>(buffer)); allocateGuard.Disable(); @@ -641,9 +646,9 @@ std::pair<int, std::unique_ptr<MemoryRuntimeAHWB>> MemoryRuntimeAHWB::create(uin return {ANEURALNETWORKS_NO_ERROR, std::move(memory)}; } -MemoryRuntimeAHWB::MemoryRuntimeAHWB(hal::hidl_memory memory, AHardwareBuffer* ahwb, +MemoryRuntimeAHWB::MemoryRuntimeAHWB(hardware::hidl_memory memory, AHardwareBuffer* ahwb, uint8_t* buffer) - : Memory(std::move(memory)), mAhwb(ahwb), mBuffer(buffer) { + : RuntimeMemory(std::move(memory)), mAhwb(ahwb), mBuffer(buffer) { CHECK(mAhwb != nullptr); CHECK(mBuffer != nullptr); } @@ -653,7 +658,7 @@ MemoryRuntimeAHWB::~MemoryRuntimeAHWB() { AHardwareBuffer_release(mAhwb); } -std::pair<int, std::unique_ptr<MemoryFromDevice>> MemoryFromDevice::create(sp<hal::IBuffer> buffer, +std::pair<int, std::unique_ptr<MemoryFromDevice>> MemoryFromDevice::create(sp<V1_3::IBuffer> buffer, uint32_t token) { if (buffer == nullptr) { LOG(ERROR) << "nullptr IBuffer for device memory."; @@ -666,8 +671,8 @@ std::pair<int, std::unique_ptr<MemoryFromDevice>> MemoryFromDevice::create(sp<ha return {ANEURALNETWORKS_NO_ERROR, std::make_unique<MemoryFromDevice>(std::move(buffer), token)}; }; -MemoryFromDevice::MemoryFromDevice(sp<hal::IBuffer> buffer, uint32_t token) - : Memory(std::move(buffer), token) {} +MemoryFromDevice::MemoryFromDevice(sp<V1_3::IBuffer> buffer, uint32_t token) + : RuntimeMemory(std::move(buffer), token) {} } // namespace nn } // namespace android diff --git a/nn/runtime/Memory.h b/nn/runtime/Memory.h index 56bf81dcd..f78ef8088 100644 --- a/nn/runtime/Memory.h +++ b/nn/runtime/Memory.h @@ -39,11 +39,13 @@ namespace android { namespace nn { +using ::android::hidl::memory::V1_0::IMemory; + class CompilationBuilder; class Device; class ExecutionBurstController; class ModelBuilder; -class PreparedModel; +class RuntimePreparedModel; // A utility template class to accumulate multiple objects and assign each // a distinct index number, starting with 0. @@ -93,12 +95,12 @@ class ObjectTracker { }; using CompilationRole = std::tuple<const CompilationBuilder*, IOType, uint32_t>; -using StepRoleCallback = std::function<void(const PreparedModel*, IOType, uint32_t)>; +using StepRoleCallback = std::function<void(const RuntimePreparedModel*, IOType, uint32_t)>; struct MemoryDescriptor { std::vector<uint32_t> dimensions; - ObjectTracker<PreparedModel> preparedModels; - std::vector<hal::BufferRole> inputRoles, outputRoles; + ObjectTracker<RuntimePreparedModel> preparedModels; + std::vector<BufferRole> inputRoles, outputRoles; }; class MemoryValidatorBase { @@ -144,7 +146,7 @@ class MemoryValidatorBase { // The data type, scale, zero point, and extra parameters of the target operand. // Other fields will be ignored, including dimensions, lifetime, location, etc. // Set to std::nullopt if undefined. - std::optional<hal::Operand> operand; + std::optional<Operand> operand; }; virtual Metadata getMetadata() const = 0; @@ -158,24 +160,24 @@ class MemoryValidatorBase { virtual bool isInitialized() const { return true; } }; -int copyIBufferToHidlMemory(const sp<hal::IBuffer>& src, const hal::hidl_memory& dst); +int copyIBufferToHidlMemory(const sp<V1_3::IBuffer>& src, const hardware::hidl_memory& dst); -int copyHidlMemoryToIBuffer(const hal::hidl_memory& src, const sp<hal::IBuffer>& dst, +int copyHidlMemoryToIBuffer(const hardware::hidl_memory& src, const sp<V1_3::IBuffer>& dst, const std::vector<uint32_t>& dimensions); // Represents a memory region. -class Memory { +class RuntimeMemory { // Disallow copy and assign to prevent slicing - DISALLOW_COPY_AND_ASSIGN(Memory); + DISALLOW_COPY_AND_ASSIGN(RuntimeMemory); public: // Custom destructor to notify any ExecutionBurstControllers currently using // this memory that it is being freed. - virtual ~Memory(); + virtual ~RuntimeMemory(); - hal::Request::MemoryPool getMemoryPool() const; - const hal::hidl_memory& getHidlMemory() const { return kHidlMemory; } - const sp<hal::IBuffer>& getIBuffer() const { return kBuffer; } + V1_3::Request::MemoryPool getMemoryPool() const; + const hardware::hidl_memory& getHidlMemory() const { return kHidlMemory; } + const sp<V1_3::IBuffer>& getIBuffer() const { return kBuffer; } virtual uint32_t getSize() const { return getHidlMemory().size(); } virtual std::optional<RunTimePoolInfo> getRunTimePoolInfo() const; @@ -196,24 +198,24 @@ class Memory { // the bursts' memory cache. void usedBy(const std::shared_ptr<ExecutionBurstController>& burst) const; - static int copy(const Memory& src, const Memory& dst); + static int copy(const RuntimeMemory& src, const RuntimeMemory& dst); protected: - Memory(hal::hidl_memory memory); - Memory(hal::hidl_memory memory, std::unique_ptr<MemoryValidatorBase> validator); - Memory(sp<hal::IBuffer> buffer, uint32_t token); + RuntimeMemory(hardware::hidl_memory memory); + RuntimeMemory(hardware::hidl_memory memory, std::unique_ptr<MemoryValidatorBase> validator); + RuntimeMemory(sp<V1_3::IBuffer> buffer, uint32_t token); // The HIDL representation for this memory. We will use one of the following values // when communicating with the drivers. - const hal::hidl_memory kHidlMemory; - const sp<hal::IBuffer> kBuffer; + const hardware::hidl_memory kHidlMemory; + const sp<V1_3::IBuffer> kBuffer; const uint32_t kToken = 0; std::unique_ptr<MemoryValidatorBase> mValidator; private: mutable std::mutex mMutex; - // mUsedBy is essentially a set of burst objects which use this Memory + // mUsedBy is essentially a set of burst objects which use this RuntimeMemory // object. However, std::weak_ptr does not have comparison operations nor a // std::hash implementation. This is because it is either a valid pointer // (non-null) if the shared object is still alive, or it is null if the @@ -238,7 +240,7 @@ class MemoryBuilder { int finish(); - std::pair<int, std::unique_ptr<Memory>> allocate() const; + std::pair<int, std::unique_ptr<RuntimeMemory>> allocate() const; private: bool badState(const char* name) const; @@ -253,7 +255,7 @@ class MemoryBuilder { // Keep track of the data type, scale, zero point, and extra parameters of the target operand. // Other fields will be ignored, including dimensions, lifetime, location, etc. // It is std::nullopt if no usage has been specified yet. - std::optional<hal::Operand> mOperand; + std::optional<Operand> mOperand; // Once the descriptor has been finished, we should not allow further modifications. bool mFinished = false; @@ -271,7 +273,7 @@ class MemoryBuilder { bool mShouldFallback = true; }; -class MemoryAshmem : public Memory { +class MemoryAshmem : public RuntimeMemory { public: // Creates a memory object containing a new android shared memory ("ashmem") // object of the size specified in bytes. Because this ashmem region can be @@ -292,13 +294,13 @@ class MemoryAshmem : public Memory { } // prefer using MemoryAshmem::create - MemoryAshmem(sp<hal::IMemory> mapped, hal::hidl_memory memory); + MemoryAshmem(sp<IMemory> mapped, hardware::hidl_memory memory); private: - const sp<hal::IMemory> kMappedMemory; + const sp<IMemory> kMappedMemory; }; -class MemoryFd : public Memory { +class MemoryFd : public RuntimeMemory { public: // Create a memory object based on input size, prot, and fd that can be sent // across HIDL. This function duplicates the provided fd, and owns the @@ -310,10 +312,10 @@ class MemoryFd : public Memory { size_t offset); // prefer using MemoryFd::create - MemoryFd(hal::hidl_memory memory); + MemoryFd(hardware::hidl_memory memory); }; -class MemoryAHWB : public Memory { +class MemoryAHWB : public RuntimeMemory { public: // Create a memory object to keep track of (but not take ownership of) the // provided AHardwareBuffer handle. @@ -323,11 +325,11 @@ class MemoryAHWB : public Memory { static std::pair<int, std::unique_ptr<MemoryAHWB>> create(const AHardwareBuffer& ahwb); // prefer using MemoryAHWB::create - MemoryAHWB(hal::hidl_memory memory, std::unique_ptr<MemoryValidatorBase> validator) - : Memory(std::move(memory), std::move(validator)) {} + MemoryAHWB(hardware::hidl_memory memory, std::unique_ptr<MemoryValidatorBase> validator) + : RuntimeMemory(std::move(memory), std::move(validator)) {} }; -class MemoryRuntimeAHWB : public Memory { +class MemoryRuntimeAHWB : public RuntimeMemory { public: // Create a memory object containing a new BLOB-mode AHardwareBuffer memory // object of the size specified in bytes. The created memory is managed and @@ -347,7 +349,7 @@ class MemoryRuntimeAHWB : public Memory { } // prefer using MemoryRuntimeAHWB::create - MemoryRuntimeAHWB(hal::hidl_memory memory, AHardwareBuffer* ahwb, uint8_t* buffer); + MemoryRuntimeAHWB(hardware::hidl_memory memory, AHardwareBuffer* ahwb, uint8_t* buffer); ~MemoryRuntimeAHWB(); private: @@ -355,21 +357,21 @@ class MemoryRuntimeAHWB : public Memory { uint8_t* const mBuffer; }; -class MemoryFromDevice : public Memory { +class MemoryFromDevice : public RuntimeMemory { public: // Create a memory object to keep track of a driver-allocated device memory. // The memory is recognized by the driver via a token. // // On success, returns ANEURALNETWORKS_NO_ERROR and a memory object. // On error, returns the appropriate NNAPI error code and nullptr. - static std::pair<int, std::unique_ptr<MemoryFromDevice>> create(sp<hal::IBuffer> buffer, + static std::pair<int, std::unique_ptr<MemoryFromDevice>> create(sp<V1_3::IBuffer> buffer, uint32_t token); // prefer using MemoryFromDevice::create - MemoryFromDevice(sp<hal::IBuffer> buffer, uint32_t token); + MemoryFromDevice(sp<V1_3::IBuffer> buffer, uint32_t token); }; -using MemoryTracker = ObjectTracker<Memory>; +using MemoryTracker = ObjectTracker<RuntimeMemory>; } // namespace nn } // namespace android diff --git a/nn/runtime/ModelArgumentInfo.cpp b/nn/runtime/ModelArgumentInfo.cpp index cf2400475..a6a8908b2 100644 --- a/nn/runtime/ModelArgumentInfo.cpp +++ b/nn/runtime/ModelArgumentInfo.cpp @@ -30,8 +30,6 @@ namespace android { namespace nn { -using namespace hal; - static const std::pair<int, ModelArgumentInfo> kBadDataModelArgumentInfo{ANEURALNETWORKS_BAD_DATA, {}}; @@ -98,33 +96,33 @@ int ModelArgumentInfo::updateDimensionInfo(const Operand& operand, mDimensions = operand.dimensions; } else { const uint32_t count = newType->dimensionCount; - mDimensions = hidl_vec<uint32_t>(count); + mDimensions = std::vector<uint32_t>(count); std::copy(&newType->dimensions[0], &newType->dimensions[count], mDimensions.begin()); } return ANEURALNETWORKS_NO_ERROR; } -hidl_vec<RequestArgument> createRequestArguments( +std::vector<Request::Argument> createRequestArguments( const std::vector<ModelArgumentInfo>& argumentInfos, const std::vector<DataLocation>& ptrArgsLocations) { const size_t count = argumentInfos.size(); - hidl_vec<RequestArgument> ioInfos(count); + std::vector<Request::Argument> ioInfos(count); uint32_t ptrArgsIndex = 0; for (size_t i = 0; i < count; i++) { const auto& info = argumentInfos[i]; switch (info.state()) { case ModelArgumentInfo::POINTER: - ioInfos[i] = {.hasNoValue = false, + ioInfos[i] = {.lifetime = Request::Argument::LifeTime::POOL, .location = ptrArgsLocations[ptrArgsIndex++], .dimensions = info.dimensions()}; break; case ModelArgumentInfo::MEMORY: - ioInfos[i] = {.hasNoValue = false, + ioInfos[i] = {.lifetime = Request::Argument::LifeTime::POOL, .location = info.locationAndLength(), .dimensions = info.dimensions()}; break; case ModelArgumentInfo::HAS_NO_VALUE: - ioInfos[i] = {.hasNoValue = true}; + ioInfos[i] = {.lifetime = Request::Argument::LifeTime::NO_VALUE}; break; default: CHECK(false); diff --git a/nn/runtime/ModelArgumentInfo.h b/nn/runtime/ModelArgumentInfo.h index 22dd34cb0..d0e2bb038 100644 --- a/nn/runtime/ModelArgumentInfo.h +++ b/nn/runtime/ModelArgumentInfo.h @@ -20,7 +20,6 @@ #include <utility> #include <vector> -#include "HalInterfaces.h" #include "NeuralNetworks.h" #include "Utils.h" @@ -38,10 +37,10 @@ class ModelArgumentInfo { ModelArgumentInfo() {} static std::pair<int, ModelArgumentInfo> createFromPointer( - const hal::Operand& operand, const ANeuralNetworksOperandType* type, + const Operand& operand, const ANeuralNetworksOperandType* type, void* data /* nullptr means HAS_NO_VALUE */, uint32_t length); static std::pair<int, ModelArgumentInfo> createFromMemory( - const hal::Operand& operand, const ANeuralNetworksOperandType* type, uint32_t poolIndex, + const Operand& operand, const ANeuralNetworksOperandType* type, uint32_t poolIndex, uint32_t offset, uint32_t length); enum State { POINTER, MEMORY, HAS_NO_VALUE, UNSPECIFIED }; @@ -78,17 +77,17 @@ class ModelArgumentInfo { return mLocationAndLength.length; } - const hal::DataLocation& locationAndLength() const { + const DataLocation& locationAndLength() const { CHECK_EQ(mState, MEMORY); return mLocationAndLength; } - hal::DataLocation& locationAndLength() { + DataLocation& locationAndLength() { CHECK_EQ(mState, MEMORY); return mLocationAndLength; } private: - int updateDimensionInfo(const hal::Operand& operand, const ANeuralNetworksOperandType* newType); + int updateDimensionInfo(const Operand& operand, const ANeuralNetworksOperandType* newType); // Whether the argument was specified as being in a Memory, as a pointer, // has no value, or has not been specified. @@ -101,16 +100,16 @@ class ModelArgumentInfo { // mDimensions is valid. State mState = UNSPECIFIED; // fixed at creation void* mBuffer = nullptr; // fixed at creation - hal::DataLocation mLocationAndLength; // can be updated after creation + DataLocation mLocationAndLength; // can be updated after creation std::vector<uint32_t> mDimensions; // can be updated after creation bool mIsSufficient = true; // can be updated after creation }; -// Convert ModelArgumentInfo to HIDL RequestArgument. For pointer arguments, use the location +// Convert ModelArgumentInfo to HIDL Request::Argument. For pointer arguments, use the location // information in ptrArgsLocations. -hal::hidl_vec<hal::RequestArgument> createRequestArguments( +std::vector<Request::Argument> createRequestArguments( const std::vector<ModelArgumentInfo>& argumentInfos, - const std::vector<hal::DataLocation>& ptrArgsLocations); + const std::vector<DataLocation>& ptrArgsLocations); } // namespace nn } // namespace android diff --git a/nn/runtime/ModelBuilder.cpp b/nn/runtime/ModelBuilder.cpp index ab63f62d1..0c506d5f3 100644 --- a/nn/runtime/ModelBuilder.cpp +++ b/nn/runtime/ModelBuilder.cpp @@ -35,8 +35,6 @@ namespace android { namespace nn { -using namespace hal; - // The maximum number of operands and operations that a model may have. const uint32_t MAX_NUMBER_OF_OPERANDS = 0xFFFFFFFE; const uint32_t MAX_NUMBER_OF_OPERATIONS = 0xFFFFFFFE; @@ -66,7 +64,7 @@ int ModelBuilder::addOperand(const ANeuralNetworksOperandType& type) { } OperandType operandType = static_cast<OperandType>(type.type); - if (isExtensionOperandType(operandType) && !TypeManager::get()->areExtensionsAllowed()) { + if (isExtension(operandType) && !TypeManager::get()->areExtensionsAllowed()) { LOG(ERROR) << "Extensions are not supported for this process."; return ANEURALNETWORKS_BAD_DATA; } @@ -77,9 +75,9 @@ int ModelBuilder::addOperand(const ANeuralNetworksOperandType& type) { } const Extension::OperandTypeInformation* info = nullptr; - if (isExtensionOperandType(operandType) && + if (isExtension(operandType) && !TypeManager::get()->getExtensionOperandTypeInfo(operandType, &info)) { - LOG(ERROR) << "Extension operand type " << toString(operandType) << " is not registered"; + LOG(ERROR) << "Extension operand type " << operandType << " is not registered"; return ANEURALNETWORKS_BAD_DATA; } NN_RETURN_IF_ERROR(validateOperandType(type, info, "ANeuralNetworksModel_addOperand", true)); @@ -92,13 +90,12 @@ int ModelBuilder::addOperand(const ANeuralNetworksOperandType& type) { mOperands.push_back({ .type = operandType, .dimensions = - hidl_vec<uint32_t>(type.dimensions, type.dimensions + type.dimensionCount), - .numberOfConsumers = 0, + std::vector<uint32_t>(type.dimensions, type.dimensions + type.dimensionCount), .scale = type.scale, .zeroPoint = type.zeroPoint, - .lifetime = OperandLifeTime::TEMPORARY_VARIABLE, + .lifetime = Operand::LifeTime::TEMPORARY_VARIABLE, .location = {.poolIndex = 0, .offset = 0, .length = 0}, - .extraParams = OperandExtraParams(), + .extraParams = {}, }); mHasOEMOperand |= isOemOperand; return ANEURALNETWORKS_NO_ERROR; @@ -122,7 +119,7 @@ int ModelBuilder::setOperandValue(uint32_t index, const void* buffer, size_t len "not 0"; return ANEURALNETWORKS_BAD_DATA; } - operand.lifetime = OperandLifeTime::NO_VALUE; + operand.lifetime = Operand::LifeTime::NO_VALUE; // The location is unused and is set to zeros. operand.location = {.poolIndex = 0, .offset = 0, .length = 0}; } else { @@ -150,14 +147,14 @@ int ModelBuilder::setOperandValue(uint32_t index, const void* buffer, size_t len uint32_t existingSize = static_cast<uint32_t>(mSmallOperandValues.size()); uint32_t extraBytes = alignBytesNeeded(existingSize, valueLength); mSmallOperandValues.resize(existingSize + extraBytes + valueLength); - operand.lifetime = OperandLifeTime::CONSTANT_COPY; + operand.lifetime = Operand::LifeTime::CONSTANT_COPY; operand.location = { .poolIndex = 0, .offset = existingSize + extraBytes, .length = valueLength}; memcpy(&mSmallOperandValues[operand.location.offset], buffer, valueLength); VLOG(MODEL) << "Copied small value to offset " << operand.location.offset; } else { VLOG(MODEL) << "Saving large value"; - operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE; + operand.lifetime = Operand::LifeTime::CONSTANT_REFERENCE; // The values for poolIndex and offset will be set when the model is finished. typedef decltype(operand.location.poolIndex) PoolIndexType; typedef decltype(operand.location.offset) OffsetType; @@ -191,7 +188,7 @@ int ModelBuilder::setOperandValueFromModel(uint32_t index, const ModelBuilder* v return ANEURALNETWORKS_BAD_DATA; } Operand& operand = mOperands[index]; - operand.lifetime = OperandLifeTime::SUBGRAPH; + operand.lifetime = Operand::LifeTime::SUBGRAPH; operand.location = { .poolIndex = 0, .offset = static_cast<uint32_t>(mReferencedModels.size()), @@ -216,17 +213,17 @@ int ModelBuilder::setOperandSymmPerChannelQuantParams( Operand& operand = mOperands[index]; if (!validateOperandSymmPerChannelQuantParams( - operand, channelQuant, + convertToV1_3(operand), channelQuant, "ANeuralNetworksModel_setOperandSymmPerChannelQuantParams")) { return ANEURALNETWORKS_BAD_DATA; } switch (operand.type) { case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: - operand.extraParams.channelQuant({ - .scales = hidl_vec<float>(channelQuant.scales, - channelQuant.scales + channelQuant.scaleCount), + operand.extraParams = Operand::SymmPerChannelQuantParams{ + .scales = std::vector<float>(channelQuant.scales, + channelQuant.scales + channelQuant.scaleCount), .channelDim = channelQuant.channelDim, - }); + }; break; default: LOG(ERROR) << "ANeuralNetworksModel_setOperandSymmPerChannelQuantParams " @@ -258,7 +255,7 @@ int ModelBuilder::setOperandExtensionData(uint32_t index, const void* data, size << "is zero"; return ANEURALNETWORKS_BAD_DATA; } - if (!isExtensionOperandType(operand.type)) { + if (!isExtension(operand.type)) { LOG(ERROR) << "ANeuralNetworksModel_setOperandExtensionData " << "setting extension data for a base operand type " << static_cast<int32_t>(operand.type); @@ -266,11 +263,11 @@ int ModelBuilder::setOperandExtensionData(uint32_t index, const void* data, size } if (data == nullptr) { - operand.extraParams.none(); + operand.extraParams = {}; } else { - operand.extraParams.extension( - hidl_vec<uint8_t>(reinterpret_cast<const uint8_t*>(data), - reinterpret_cast<const uint8_t*>(data) + length)); + operand.extraParams = Operand::ExtensionParams( + std::vector<uint8_t>(reinterpret_cast<const uint8_t*>(data), + reinterpret_cast<const uint8_t*>(data) + length)); } return ANEURALNETWORKS_NO_ERROR; } @@ -283,7 +280,7 @@ int ModelBuilder::copyLargeValuesToSharedMemory() { size_t poolSize = 0; for (LargeValue& l : mLargeOperandValues) { Operand& operand = mOperands[l.operandIndex]; - nnAssert(operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE); + CHECK_EQ(operand.lifetime, Operand::LifeTime::CONSTANT_REFERENCE); poolSize += alignBytesNeeded(poolSize, operand.location.length); operand.location.offset = poolSize; poolSize += operand.location.length; @@ -308,8 +305,8 @@ int ModelBuilder::copyLargeValuesToSharedMemory() { return ANEURALNETWORKS_NO_ERROR; } -int ModelBuilder::setOperandValueFromMemory(uint32_t index, const Memory* memory, uint32_t offset, - size_t length) { +int ModelBuilder::setOperandValueFromMemory(uint32_t index, const RuntimeMemory* memory, + uint32_t offset, size_t length) { VLOG(MODEL) << __func__ << " for operand " << index << " offset " << offset << " size " << length; if (badState("setOperandValueFromMemory")) { @@ -339,7 +336,7 @@ int ModelBuilder::setOperandValueFromMemory(uint32_t index, const Memory* memory nullptr, offset, length)) { return ANEURALNETWORKS_BAD_DATA; } - operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE; + operand.lifetime = Operand::LifeTime::CONSTANT_REFERENCE; operand.location = {.poolIndex = mMemories.add(memory), .offset = offset, .length = static_cast<uint32_t>(length)}; @@ -354,7 +351,7 @@ int ModelBuilder::addOperation(ANeuralNetworksOperationType type, uint32_t input } OperationType operationType = static_cast<OperationType>(type); - if (isExtensionOperationType(operationType) && !TypeManager::get()->areExtensionsAllowed()) { + if (isExtension(operationType) && !TypeManager::get()->areExtensionsAllowed()) { LOG(ERROR) << "Extensions are not supported for this process."; return ANEURALNETWORKS_BAD_DATA; } @@ -362,7 +359,7 @@ int ModelBuilder::addOperation(ANeuralNetworksOperationType type, uint32_t input LOG(WARNING) << "OEM_OPERATION is deprecated. Use Extensions instead."; } - if (!isExtensionOperationType(operationType)) { + if (!isExtension(operationType)) { if (!validCode(kNumberOfOperationTypes, kNumberOfOperationTypesOEM, type)) { LOG(ERROR) << "ANeuralNetworksModel_addOperation invalid operation type " << type; return ANEURALNETWORKS_BAD_DATA; @@ -370,8 +367,8 @@ int ModelBuilder::addOperation(ANeuralNetworksOperationType type, uint32_t input } auto isValidSubgraphReference = [this](const Operand& modelOperand) -> bool { - NN_RET_CHECK(modelOperand.type == OperandType::SUBGRAPH) - << "Unexpected operand type: " << toString(modelOperand.type); + NN_RET_CHECK_EQ(modelOperand.type, OperandType::SUBGRAPH) + << "Unexpected operand type: " << modelOperand.type; NN_RET_CHECK_LT(modelOperand.location.offset, referencedModelCount()) << "Invalid subgraph model reference"; return true; @@ -405,14 +402,11 @@ int ModelBuilder::addOperation(ANeuralNetworksOperationType type, uint32_t input mOperations.push_back({ .type = operationType, - .inputs = hidl_vec<uint32_t>(inputs, inputs + inputCount), - .outputs = hidl_vec<uint32_t>(outputs, outputs + outputCount), + .inputs = std::vector<uint32_t>(inputs, inputs + inputCount), + .outputs = std::vector<uint32_t>(outputs, outputs + outputCount), }); - for (uint32_t i : mOperations.back().inputs) { - mOperands[i].numberOfConsumers++; - } mHasOEMOperation |= (operationType == OperationType::OEM_OPERATION); - mHasExtensionOperation |= isExtensionOperationType(operationType); + mHasExtensionOperation |= isExtension(operationType); return ANEURALNETWORKS_NO_ERROR; } @@ -437,7 +431,7 @@ int ModelBuilder::identifyInputsAndOutputs(uint32_t inputCount, const uint32_t* // Makes a copy of the index list, validates the arguments, and changes // the lifetime info of the corresponding operand. auto setArguments = [&](std::vector<uint32_t>* indexVector, uint32_t indexCount, - const uint32_t* indexList, OperandLifeTime lifetime) -> bool { + const uint32_t* indexList, Operand::LifeTime lifetime) -> bool { indexVector->resize(indexCount); for (uint32_t i = 0; i < indexCount; i++) { const uint32_t operandIndex = indexList[i]; @@ -451,7 +445,7 @@ int ModelBuilder::identifyInputsAndOutputs(uint32_t inputCount, const uint32_t* } (*indexVector)[i] = operandIndex; Operand& operand = mOperands[operandIndex]; - if (operand.lifetime != OperandLifeTime::TEMPORARY_VARIABLE) { + if (operand.lifetime != Operand::LifeTime::TEMPORARY_VARIABLE) { LOG(ERROR) << "ANeuralNetworksModel_identifyInputsAndOutputs Can't set operand " << operandIndex << " to be an input or output. Check that it's not a constant or " @@ -463,8 +457,8 @@ int ModelBuilder::identifyInputsAndOutputs(uint32_t inputCount, const uint32_t* return true; }; - if (!setArguments(&mInputIndexes, inputCount, inputs, OperandLifeTime::SUBGRAPH_INPUT) || - !setArguments(&mOutputIndexes, outputCount, outputs, OperandLifeTime::SUBGRAPH_OUTPUT)) { + if (!setArguments(&mInputIndexes, inputCount, inputs, Operand::LifeTime::SUBGRAPH_INPUT) || + !setArguments(&mOutputIndexes, outputCount, outputs, Operand::LifeTime::SUBGRAPH_OUTPUT)) { return ANEURALNETWORKS_BAD_DATA; } @@ -523,8 +517,8 @@ int ModelBuilder::finish() { // NOTE: Must copyLargeValuesToSharedMemory() before validation; otherwise, // a CONSTANT_REFERENCE operand will not have correct .poolIndex, and // validation will not work properly. - const Model modelForValidation = makeHidlModel(); - if (!validateModel(modelForValidation, ValidationMode::RUNTIME)) { + const Model modelForValidation = makeModel(); + if (!validateModel(convertToV1_3(modelForValidation), ValidationMode::RUNTIME)) { LOG(ERROR) << "ANeuralNetworksModel_finish called on invalid model"; mInvalidModel = true; return ANEURALNETWORKS_BAD_DATA; @@ -542,12 +536,12 @@ int ModelBuilder::finish() { static void logRemoval(const Operation& operation, uint32_t count, const std::vector<Operand>& operands) { std::ostringstream message; - message << "Operation " << toString(operation.type) << " with inputs {"; + message << "Operation " << operation.type << " with inputs {"; for (uint32_t i = 0; i < operation.inputs.size(); ++i) { if (i != 0) { message << ", "; } - message << toString(operands[operation.inputs[i]].type); + message << operands[operation.inputs[i]].type; } message << "} has trailing optional inputs set to default values. Removing " << count << " trailing inputs."; @@ -566,9 +560,6 @@ void ModelBuilder::removeTrailingArgumentsWithDefaultValues() { const uint32_t inputCount = operation.inputs.size(); CHECK_LT(count, inputCount); const uint32_t newInputCount = inputCount - count; - for (uint32_t i = newInputCount; i < inputCount; ++i) { - --mOperands[operation.inputs[i]].numberOfConsumers; - } operation.inputs.resize(newInputCount); } } @@ -583,12 +574,16 @@ enum class TailSpec { // See countMatchingTrailingArguments(). static bool matchesSpec(TailSpec spec, const Operand& operand, const std::vector<uint8_t>& mSmallOperandValues) { - if (operand.lifetime != OperandLifeTime::CONSTANT_COPY) { + const void* valuePtr = nullptr; + if (operand.lifetime == Operand::LifeTime::CONSTANT_COPY) { + valuePtr = static_cast<const void*>(&mSmallOperandValues[operand.location.offset]); + } else if (operand.lifetime == Operand::LifeTime::POINTER) { + valuePtr = std::get<const void*>(operand.location.pointer); + } else { // CONSTANT_REFERENCE operands are not supported to avoid mapping memory // during compilation. return false; } - auto valuePtr = static_cast<const void*>(&mSmallOperandValues[operand.location.offset]); switch (spec) { case TailSpec::BOOL_FALSE: return operand.type == OperandType::BOOL && @@ -818,8 +813,8 @@ bool ModelBuilder::sortIntoRunOrder() { count = 0; for (uint32_t operandIndex : mOperations[operationIndex].inputs) { auto lifetime = mOperands[operandIndex].lifetime; - if (lifetime == OperandLifeTime::TEMPORARY_VARIABLE || - lifetime == OperandLifeTime::SUBGRAPH_OUTPUT) { + if (lifetime == Operand::LifeTime::TEMPORARY_VARIABLE || + lifetime == Operand::LifeTime::SUBGRAPH_OUTPUT) { count++; operandToOperations.insert( std::pair<uint32_t, uint32_t>(operandIndex, operationIndex)); @@ -865,38 +860,38 @@ bool ModelBuilder::sortIntoRunOrder() { return true; } -// A helper class to simplify state management when creating a HIDL model. -class ModelBuilder::HidlModelMaker { +// A helper class to simplify state management when creating a Model. +class ModelBuilder::ModelMaker { public: static Model run(const ModelBuilder* model); private: - static Subgraph makeSubgraph(const ModelBuilder* model); - HidlModelMaker() {} - Model makeHidlModel(const ModelBuilder* mainModel); + static Model::Subgraph makeSubgraph(const ModelBuilder* model); + ModelMaker() {} + Model makeModel(const ModelBuilder* mainModel); uint32_t addSubgraph(const ModelBuilder* refModel); - void updateOperandLocations(const ModelBuilder* refModel, Subgraph* subgraph); + void updateOperandLocations(const ModelBuilder* refModel, Model::Subgraph* subgraph); void addExtensions(const ModelBuilder* model); void addExtensionWithPrefix(uint16_t prefix); - std::vector<Subgraph> mRefSubgraphs; - std::vector<uint8_t> mOperandValues; + std::vector<Model::Subgraph> mRefSubgraphs; + Model::OperandValues mOperandValues; MemoryTracker mMemories; - std::vector<ExtensionNameAndPrefix> mExtensionNameToPrefix; + std::vector<Model::ExtensionNameAndPrefix> mExtensionNameToPrefix; std::set<uint16_t> mPrefixSet; }; -Model ModelBuilder::makeHidlModel() const { - // TODO: Cache the HIDL model to speed up subsequent calls. - return HidlModelMaker::run(this); +Model ModelBuilder::makeModel() const { + // TODO: Cache the Model to speed up subsequent calls. + return ModelMaker::run(this); } -Model ModelBuilder::HidlModelMaker::run(const ModelBuilder* model) { - // run() ensures the state of HidlModelMaker is destroyed after the call. - return HidlModelMaker().makeHidlModel(model); +Model ModelBuilder::ModelMaker::run(const ModelBuilder* model) { + // run() ensures the state of ModelMaker is destroyed after the call. + return ModelMaker().makeModel(model); } -Model ModelBuilder::HidlModelMaker::makeHidlModel(const ModelBuilder* mainModel) { +Model ModelBuilder::ModelMaker::makeModel(const ModelBuilder* mainModel) { addExtensions(mainModel); Model model; model.main = makeSubgraph(mainModel); @@ -905,14 +900,14 @@ Model ModelBuilder::HidlModelMaker::makeHidlModel(const ModelBuilder* mainModel) model.operandValues = std::move(mOperandValues); model.pools.resize(mMemories.size()); std::transform(mMemories.begin(), mMemories.end(), model.pools.begin(), - [](const Memory* m) { return m->getHidlMemory(); }); + [](const RuntimeMemory* m) { return uncheckedConvert(m->getHidlMemory()); }); model.relaxComputationFloat32toFloat16 = mainModel->mRelaxComputationFloat32toFloat16; model.extensionNameToPrefix = std::move(mExtensionNameToPrefix); return model; } -Subgraph ModelBuilder::HidlModelMaker::makeSubgraph(const ModelBuilder* model) { - Subgraph subgraph; +Model::Subgraph ModelBuilder::ModelMaker::makeSubgraph(const ModelBuilder* model) { + Model::Subgraph subgraph; subgraph.operands = model->mOperands; subgraph.operations = model->mOperations; subgraph.inputIndexes = model->mInputIndexes; @@ -920,27 +915,22 @@ Subgraph ModelBuilder::HidlModelMaker::makeSubgraph(const ModelBuilder* model) { return subgraph; } -void ModelBuilder::HidlModelMaker::updateOperandLocations(const ModelBuilder* refModel, - Subgraph* subgraph) { +void ModelBuilder::ModelMaker::updateOperandLocations(const ModelBuilder* refModel, + Model::Subgraph* subgraph) { for (Operand& operand : subgraph->operands) { - if (operand.lifetime == OperandLifeTime::CONSTANT_COPY) { + if (operand.lifetime == Operand::LifeTime::CONSTANT_COPY) { uint32_t valueLength = operand.location.length; - uint32_t existingSize = mOperandValues.size(); - uint32_t extraBytes = alignBytesNeeded(existingSize, valueLength); uint32_t originalOffset = operand.location.offset; - uint32_t offset = existingSize + extraBytes; - mOperandValues.resize(offset + valueLength); - memcpy(&mOperandValues[offset], &refModel->mSmallOperandValues[originalOffset], - valueLength); - operand.location.offset = offset; - } else if (operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE) { + operand.location = mOperandValues.append(&refModel->mSmallOperandValues[originalOffset], + valueLength); + } else if (operand.lifetime == Operand::LifeTime::CONSTANT_REFERENCE) { uint32_t originalPoolIndex = operand.location.poolIndex; operand.location.poolIndex = mMemories.add(refModel->mMemories[originalPoolIndex]); } } // Do recursive calls at the end to improve locality of mOperandValues. for (Operand& operand : subgraph->operands) { - if (operand.lifetime == OperandLifeTime::SUBGRAPH) { + if (operand.lifetime == Operand::LifeTime::SUBGRAPH) { uint32_t refModelIndex = operand.location.offset; // TODO(b/147875885): Avoid creating duplicate refSubgraphs when // a single refModel is referenced multiple times. @@ -949,23 +939,22 @@ void ModelBuilder::HidlModelMaker::updateOperandLocations(const ModelBuilder* re } } -uint32_t ModelBuilder::HidlModelMaker::addSubgraph(const ModelBuilder* refModel) { +uint32_t ModelBuilder::ModelMaker::addSubgraph(const ModelBuilder* refModel) { uint32_t index = mRefSubgraphs.size(); mRefSubgraphs.push_back(makeSubgraph(refModel)); updateOperandLocations(refModel, &mRefSubgraphs.back()); return index; } -void ModelBuilder::HidlModelMaker::addExtensions(const ModelBuilder* model) { - constexpr uint8_t kLowBitsType = static_cast<uint8_t>(ExtensionTypeEncoding::LOW_BITS_TYPE); +void ModelBuilder::ModelMaker::addExtensions(const ModelBuilder* model) { for (const auto& operand : model->mOperands) { - if (isExtensionOperandType(operand.type)) { - addExtensionWithPrefix(static_cast<uint32_t>(operand.type) >> kLowBitsType); + if (isExtension(operand.type)) { + addExtensionWithPrefix(static_cast<uint32_t>(operand.type) >> kExtensionTypeBits); } } for (const auto& operation : model->mOperations) { - if (isExtensionOperationType(operation.type)) { - addExtensionWithPrefix(static_cast<uint32_t>(operation.type) >> kLowBitsType); + if (isExtension(operation.type)) { + addExtensionWithPrefix(static_cast<uint32_t>(operation.type) >> kExtensionTypeBits); } } for (const auto& refModel : model->mReferencedModels) { @@ -973,7 +962,7 @@ void ModelBuilder::HidlModelMaker::addExtensions(const ModelBuilder* model) { } } -void ModelBuilder::HidlModelMaker::addExtensionWithPrefix(uint16_t prefix) { +void ModelBuilder::ModelMaker::addExtensionWithPrefix(uint16_t prefix) { if (!mPrefixSet.insert(prefix).second) { return; } diff --git a/nn/runtime/ModelBuilder.h b/nn/runtime/ModelBuilder.h index 2de68b392..9dd93ffc6 100644 --- a/nn/runtime/ModelBuilder.h +++ b/nn/runtime/ModelBuilder.h @@ -23,7 +23,6 @@ #include <memory> #include <vector> -#include "HalInterfaces.h" #include "Memory.h" #include "NeuralNetworks.h" #include "Utils.h" @@ -34,7 +33,7 @@ namespace nn { class CompilationBuilder; class Device; class ExecutionPlan; -class Memory; +class RuntimeMemory; class ModelBuilder { public: @@ -44,7 +43,7 @@ class ModelBuilder { // Adds an operand to the model. int addOperand(const ANeuralNetworksOperandType& type); int setOperandValue(uint32_t index, const void* buffer, size_t length); - int setOperandValueFromMemory(uint32_t index, const Memory* memory, uint32_t offset, + int setOperandValueFromMemory(uint32_t index, const RuntimeMemory* memory, uint32_t offset, size_t length); int setOperandValueFromModel(uint32_t index, const ModelBuilder* value); int setOperandSymmPerChannelQuantParams( @@ -72,7 +71,7 @@ class ModelBuilder { const std::vector<std::shared_ptr<Device>>& devices, bool explicitDeviceList = false); - hal::Model makeHidlModel() const; + Model makeModel() const; uint32_t operandCount() const { // We don't allow more than uint32_t worth of operands @@ -89,7 +88,7 @@ class ModelBuilder { return mInputIndexes[i]; } const std::vector<uint32_t>& getInputOperandIndexes() const { return mInputIndexes; } - const hal::Operand& getInputOperand(uint32_t i) const { + const Operand& getInputOperand(uint32_t i) const { uint32_t index = getInputOperandIndex(i); CHECK_LT(index, mOperands.size()); return mOperands[index]; @@ -99,15 +98,15 @@ class ModelBuilder { return mOutputIndexes[i]; } const std::vector<uint32_t>& getOutputOperandIndexes() const { return mOutputIndexes; } - const hal::Operand& getOutputOperand(uint32_t i) const { + const Operand& getOutputOperand(uint32_t i) const { uint32_t index = getOutputOperandIndex(i); CHECK_LT(index, mOperands.size()); return mOperands[index]; } - const hal::Operand& getOperand(uint32_t index) const { return mOperands[index]; } - const hal::Operation& getOperation(uint32_t index) const { return mOperations[index]; } + const Operand& getOperand(uint32_t index) const { return mOperands[index]; } + const Operation& getOperation(uint32_t index) const { return mOperations[index]; } const MemoryTracker& getMemories() const { return mMemories; } - const std::vector<hal::Operation>& getOperations() const { return mOperations; } + const std::vector<Operation>& getOperations() const { return mOperations; } const std::vector<uint32_t>& getSortedOperationMapping() const { return mSortedOperationIndexMap; } @@ -121,8 +120,8 @@ class ModelBuilder { CHECK_LT(i, mReferencedModels.size()); return mReferencedModels[i]; } - const ModelBuilder* getReferencedModel(const hal::Operand& operand) const { - CHECK(operand.lifetime == hal::OperandLifeTime::SUBGRAPH); + const ModelBuilder* getReferencedModel(const Operand& operand) const { + CHECK(operand.lifetime == Operand::LifeTime::SUBGRAPH); return getReferencedModel(operand.location.offset); } @@ -174,7 +173,7 @@ class ModelBuilder { // optional arguments are set to default values. This transformation enables // more drivers to execute the model. See http://b/147105700. void removeTrailingArgumentsWithDefaultValues(); - uint32_t getNumTrailingArgumentsToRemove(const hal::Operation& operation) const; + uint32_t getNumTrailingArgumentsToRemove(const Operation& operation) const; // Sorts the operations to be in the correct order for single threaded // node-at-a-time execution. @@ -184,7 +183,7 @@ class ModelBuilder { int copyLargeValuesToSharedMemory(); // The operations of the graph. - std::vector<hal::Operation> mOperations; + std::vector<Operation> mOperations; // The mapping from sorted index to the original index of operations in mOperations. // mSortedOperationIndexMap is empty before sortIntoRunOrder() is called. std::vector<uint32_t> mSortedOperationIndexMap; @@ -193,7 +192,7 @@ class ModelBuilder { // Is at least one of those operations an extension operation? bool mHasExtensionOperation = false; // The description of the operands of the graph. - std::vector<hal::Operand> mOperands; + std::vector<Operand> mOperands; // Is at least one of those operands an OEM operand? bool mHasOEMOperand = false; // The indexes of input operands of the model. @@ -233,7 +232,7 @@ class ModelBuilder { // Models referenced by operands in this model. std::vector<const ModelBuilder*> mReferencedModels; - class HidlModelMaker; + class ModelMaker; }; } // namespace nn diff --git a/nn/runtime/NeuralNetworks.cpp b/nn/runtime/NeuralNetworks.cpp index f5206c866..0ccb6468c 100644 --- a/nn/runtime/NeuralNetworks.cpp +++ b/nn/runtime/NeuralNetworks.cpp @@ -22,6 +22,7 @@ #include "NeuralNetworks.h" +#include <nnapi/Types.h> #include <vndk/hardware_buffer.h> #include <algorithm> @@ -35,7 +36,6 @@ #include "ControlFlow.h" #include "Event.h" #include "ExecutionBuilder.h" -#include "HalInterfaces.h" #include "Manager.h" #include "Memory.h" #include "MetaModel.h" @@ -46,7 +46,7 @@ #include "Utils.h" using namespace android::nn; -using namespace android::nn::hal; +using android::sp; // Make sure the constants defined in the header files have not changed values. // IMPORTANT: When adding new values, update kNumberOfDataTypes or kNumberOfDataTypesOEM @@ -558,12 +558,14 @@ static_assert(static_cast<int32_t>(DeviceType::ACCELERATOR) == ANEURALNETWORKS_D // Make sure that the constants are compatible with the values defined in // hardware/interfaces/neuralnetworks/1.3/types.hal. -static_assert(android::nn::convertToHalPriority(ANEURALNETWORKS_PRIORITY_LOW) == Priority::LOW, +static_assert(android::nn::convertToCanonicalPriority(ANEURALNETWORKS_PRIORITY_LOW) == + Priority::LOW, "ANEURALNETWORKS_PRIORITY_LOW does not map to Priority::LOW"); -static_assert(android::nn::convertToHalPriority(ANEURALNETWORKS_PRIORITY_MEDIUM) == +static_assert(android::nn::convertToCanonicalPriority(ANEURALNETWORKS_PRIORITY_MEDIUM) == Priority::MEDIUM, "ANEURALNETWORKS_PRIORITY_MEDIUM does not map to Priority::MEDIUM"); -static_assert(android::nn::convertToHalPriority(ANEURALNETWORKS_PRIORITY_HIGH) == Priority::HIGH, +static_assert(android::nn::convertToCanonicalPriority(ANEURALNETWORKS_PRIORITY_HIGH) == + Priority::HIGH, "ANEURALNETWORKS_PRIORITY_HIGH does not map to Priority::HIGH"); // Asserts for ANeuralNetworksOperandType memory layout @@ -597,9 +599,8 @@ static_assert(alignof(ANeuralNetworksSymmPerChannelQuantParams) == alignof(void* // Asserts for compilation caching static_assert(ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN == 32, "ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN has changed"); -static_assert(static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) == - ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN, - "Constant::BYTE_SIZE_OF_CACHE_TOKEN != ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN"); +static_assert(ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN == kByteSizeOfCacheToken, + "ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN != kByteSizeOfCacheToken"); // Asserts for compilation priority static_assert(ANEURALNETWORKS_PRIORITY_LOW == 90, "ANEURALNETWORKS_PRIORITY_LOW has changed"); @@ -609,14 +610,6 @@ static_assert(ANEURALNETWORKS_PRIORITY_HIGH == 110, "ANEURALNETWORKS_PRIORITY_HI static_assert(ANEURALNETWORKS_PRIORITY_DEFAULT == ANEURALNETWORKS_PRIORITY_MEDIUM, "ANEURALNETWORKS_PRIORITY_DEFAULT has changed"); -// Asserts for loop timeout duration -static_assert(static_cast<uint64_t>(LoopTimeoutDurationNs::DEFAULT) == - operation_while::kTimeoutNsDefault, - "LoopTimeoutDurationNs::DEFAULT != operation_while::kTimeoutNsDefault"); -static_assert(static_cast<uint64_t>(LoopTimeoutDurationNs::MAXIMUM) == - operation_while::kTimeoutNsMaximum, - "LoopTimeoutDurationNs::MAXIMUM != operation_while::kTimeoutNsMaximum"); - int ANeuralNetworks_getDeviceCount(uint32_t* numDevices) { if (numDevices == nullptr) { LOG(ERROR) << "ANeuralNetworks_getDeviceCount passed a nullptr"; @@ -718,7 +711,7 @@ int ANeuralNetworksModel_getSupportedOperationsForDevices( return ANEURALNETWORKS_BAD_STATE; } - const Model hidlModel = m->makeHidlModel(); + const Model canonicalModel = m->makeModel(); const std::vector<uint32_t>& opMap = m->getSortedOperationMapping(); // init the output array to false for all the operations. std::fill(supportedOps, supportedOps + opMap.size(), false); @@ -737,7 +730,7 @@ int ANeuralNetworksModel_getSupportedOperationsForDevices( } Device* d = reinterpret_cast<Device*>(const_cast<ANeuralNetworksDevice*>(devices[i])); - const MetaModel metaModel(hidlModel, DeviceManager::get()->strictSlicing()); + const MetaModel metaModel(canonicalModel, DeviceManager::get()->strictSlicing()); const std::vector<bool> supportsByDevice = d->getSupportedOperations(metaModel); for (uint32_t j = 0; j < supportsByDevice.size(); j++) { uint32_t originalIdx = opMap[j]; @@ -988,9 +981,9 @@ int ANeuralNetworksMemory_copy(const ANeuralNetworksMemory* src, const ANeuralNe LOG(ERROR) << "ANeuralNetworksMemory_copy passed a nullptr"; return ANEURALNETWORKS_UNEXPECTED_NULL; } - const Memory* s = reinterpret_cast<const Memory*>(src); - const Memory* d = reinterpret_cast<const Memory*>(dst); - return Memory::copy(*s, *d); + const RuntimeMemory* s = reinterpret_cast<const RuntimeMemory*>(src); + const RuntimeMemory* d = reinterpret_cast<const RuntimeMemory*>(dst); + return RuntimeMemory::copy(*s, *d); } int ANeuralNetworksMemory_createFromFd(size_t size, int prot, int fd, size_t offset, @@ -1024,7 +1017,7 @@ int ANeuralNetworksMemory_createFromAHardwareBuffer(const AHardwareBuffer* ahwb, void ANeuralNetworksMemory_free(ANeuralNetworksMemory* memory) { NNTRACE_RT(NNTRACE_PHASE_TERMINATION, "ANeuralNetworksMemory_free"); // No validation. Free of nullptr is valid. - Memory* m = reinterpret_cast<Memory*>(memory); + RuntimeMemory* m = reinterpret_cast<RuntimeMemory*>(memory); delete m; } @@ -1091,7 +1084,7 @@ int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel* model, LOG(ERROR) << "ANeuralNetworksModel_setOperandValue passed a nullptr"; return ANEURALNETWORKS_UNEXPECTED_NULL; } - const Memory* mem = reinterpret_cast<const Memory*>(memory); + const RuntimeMemory* mem = reinterpret_cast<const RuntimeMemory*>(memory); ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model); return m->setOperandValueFromMemory(index, mem, offset, length); } @@ -1302,7 +1295,7 @@ int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution* execut return ANEURALNETWORKS_UNEXPECTED_NULL; } - const Memory* m = reinterpret_cast<const Memory*>(memory); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory); ExecutionBuilder* r = reinterpret_cast<ExecutionBuilder*>(execution); return r->setInputFromMemory(index, type, m, offset, length); } @@ -1330,7 +1323,7 @@ int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution* execu } ExecutionBuilder* r = reinterpret_cast<ExecutionBuilder*>(execution); - const Memory* m = reinterpret_cast<const Memory*>(memory); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory); return r->setOutputFromMemory(index, type, m, offset, length); } diff --git a/nn/runtime/TypeManager.cpp b/nn/runtime/TypeManager.cpp index 03fac20ac..932dcc741 100644 --- a/nn/runtime/TypeManager.cpp +++ b/nn/runtime/TypeManager.cpp @@ -48,11 +48,7 @@ inline bool StartsWith(std::string_view sv, std::string_view prefix) { namespace { -using namespace hal; - -const uint8_t kLowBitsType = static_cast<uint8_t>(ExtensionTypeEncoding::LOW_BITS_TYPE); -const uint32_t kMaxPrefix = - (1 << static_cast<uint8_t>(ExtensionTypeEncoding::HIGH_BITS_PREFIX)) - 1; +constexpr uint32_t kMaxPrefix = (1 << kExtensionPrefixBits) - 1; // Checks if the two structures contain the same information. The order of // operand types within the structures does not matter. @@ -235,7 +231,7 @@ bool TypeManager::getExtensionType(const char* extensionName, uint16_t typeWithi int32_t* type) { uint16_t prefix; NN_RET_CHECK(getExtensionPrefix(extensionName, &prefix)); - *type = (prefix << kLowBitsType) | typeWithinExtension; + *type = (prefix << kExtensionTypeBits) | typeWithinExtension; return true; } @@ -249,8 +245,8 @@ bool TypeManager::getExtensionInfo(uint16_t prefix, const Extension** extension) bool TypeManager::getExtensionOperandTypeInfo( OperandType type, const Extension::OperandTypeInformation** info) const { uint32_t operandType = static_cast<uint32_t>(type); - uint16_t prefix = operandType >> kLowBitsType; - uint16_t typeWithinExtension = operandType & ((1 << kLowBitsType) - 1); + uint16_t prefix = operandType >> kExtensionTypeBits; + uint16_t typeWithinExtension = operandType & ((1 << kExtensionTypeBits) - 1); const Extension* extension; NN_RET_CHECK(getExtensionInfo(prefix, &extension)) << "Cannot find extension corresponding to prefix " << prefix; @@ -268,7 +264,7 @@ bool TypeManager::getExtensionOperandTypeInfo( } bool TypeManager::isTensorType(OperandType type) const { - if (!isExtensionOperandType(type)) { + if (!isExtension(type)) { return !nonExtensionOperandTypeIsScalar(static_cast<int>(type)); } const Extension::OperandTypeInformation* info; @@ -278,7 +274,7 @@ bool TypeManager::isTensorType(OperandType type) const { uint32_t TypeManager::getSizeOfData(OperandType type, const std::vector<uint32_t>& dimensions) const { - if (!isExtensionOperandType(type)) { + if (!isExtension(type)) { return nonExtensionOperandSizeOfData(type, dimensions); } const Extension::OperandTypeInformation* info; @@ -286,9 +282,9 @@ uint32_t TypeManager::getSizeOfData(OperandType type, return info->isTensor ? sizeOfTensorData(info->byteSize, dimensions) : info->byteSize; } -bool TypeManager::sizeOfDataOverflowsUInt32(hal::OperandType type, +bool TypeManager::sizeOfDataOverflowsUInt32(OperandType type, const std::vector<uint32_t>& dimensions) const { - if (!isExtensionOperandType(type)) { + if (!isExtension(type)) { return nonExtensionOperandSizeOfDataOverflowsUInt32(type, dimensions); } const Extension::OperandTypeInformation* info; diff --git a/nn/runtime/TypeManager.h b/nn/runtime/TypeManager.h index a06ddb6ee..5236ba7f0 100644 --- a/nn/runtime/TypeManager.h +++ b/nn/runtime/TypeManager.h @@ -48,18 +48,18 @@ class TypeManager { // Looks up information about the extension corresponding to the given prefix // // Returns false if no extension corresponds to the given prefix. - bool getExtensionInfo(uint16_t prefix, const hal::Extension** extension) const; + bool getExtensionInfo(uint16_t prefix, const Extension** extension) const; // Looks up information about an extension operand type // // Returns false if the extension or type is unknown. - bool getExtensionOperandTypeInfo(hal::OperandType type, - const hal::Extension::OperandTypeInformation** info) const; + bool getExtensionOperandTypeInfo(OperandType type, + const Extension::OperandTypeInformation** info) const; // Returns true if an operand type is a tensor type. // // Aborts if the type is an unknown extension type. - bool isTensorType(hal::OperandType type) const; + bool isTensorType(OperandType type) const; // Returns the amount of space needed to store a value of the dimensions and // type of this operand. For a tensor with unspecified rank or at least one @@ -67,7 +67,7 @@ class TypeManager { // // Aborts if the type is an unknown extension type. // Aborts if the size would overflow the return type. - uint32_t getSizeOfData(const hal::Operand& operand) const { + uint32_t getSizeOfData(const Operand& operand) const { return getSizeOfData(operand.type, operand.dimensions); } @@ -76,14 +76,13 @@ class TypeManager { // unspecified dimension, returns zero. // // Aborts if the type is an unknown extension type. - uint32_t getSizeOfData(hal::OperandType type, const std::vector<uint32_t>& dimensions) const; + uint32_t getSizeOfData(OperandType type, const std::vector<uint32_t>& dimensions) const; // Returns true if the amount of space needed to store a value of the specified // dimensions and element size overflows the uint32_t type. // // See also TypeManager::sizeOfDataOverflowsUInt32(). - bool sizeOfDataOverflowsUInt32(hal::OperandType type, - const std::vector<uint32_t>& dimensions) const; + bool sizeOfDataOverflowsUInt32(OperandType type, const std::vector<uint32_t>& dimensions) const; // Returns true if extensions usage is allowed in current process. bool areExtensionsAllowed() const { return mExtensionsAllowed; } @@ -93,7 +92,7 @@ class TypeManager { // Registers an extension. // // Returns true if the registration was successful. - bool forTest_registerExtension(const hal::Extension& extension) { + bool forTest_registerExtension(const Extension& extension) { return registerExtension(extension, "INTERNAL TEST"); } @@ -135,7 +134,7 @@ class TypeManager { private: TypeManager(); void findAvailableExtensions(); - bool registerExtension(hal::Extension extension, const std::string& deviceName); + bool registerExtension(Extension extension, const std::string& deviceName); // Returns the numeric "prefix" value corresponding to an extension. // @@ -145,7 +144,7 @@ class TypeManager { const DeviceManager* mDeviceManager = DeviceManager::get(); // Contains all registered extensions. - std::map<std::string, hal::Extension> mExtensionNameToExtension; + std::map<std::string, Extension> mExtensionNameToExtension; // Contains the name of the first discovered device that supports an // extension. Used for error reporting. @@ -160,7 +159,7 @@ class TypeManager { std::map<std::string, uint16_t> mExtensionNameToPrefix; // Entries of mPrefixToExtension point into mExtensionNameToExtension. // prefix=0 corresponds to no extension and should never be looked up. - std::vector<hal::Extension*> mPrefixToExtension = {nullptr}; + std::vector<Extension*> mPrefixToExtension = {nullptr}; // True if Extensions can be used in current process. bool mExtensionsAllowed = false; diff --git a/nn/runtime/VersionedInterfaces.cpp b/nn/runtime/VersionedInterfaces.cpp index ccb29dc22..fce558c38 100644 --- a/nn/runtime/VersionedInterfaces.cpp +++ b/nn/runtime/VersionedInterfaces.cpp @@ -18,13 +18,12 @@ #include "VersionedInterfaces.h" -#include <fcntl.h> - #include <android-base/logging.h> #include <android-base/properties.h> #include <android-base/scopeguard.h> #include <android-base/thread_annotations.h> #include <cutils/native_handle.h> +#include <fcntl.h> #include <algorithm> #include <chrono> @@ -104,18 +103,14 @@ namespace nn { // anonymous namespace namespace { -using namespace hal; - -const Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; - -void sendFailureMessage(IPreparedModelCallback* cb) { +void sendFailureMessage(V1_3::IPreparedModelCallback* cb) { CHECK(cb != nullptr); - cb->notify_1_3(ErrorStatus::GENERAL_FAILURE, nullptr); + cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr); } // This class is thread safe template <typename Callback> -class DeathHandler : public hidl_death_recipient { +class DeathHandler : public hardware::hidl_death_recipient { public: void serviceDied(uint64_t /*cookie*/, const wp<hidl::base::V1_0::IBase>& /*who*/) override { LOG(ERROR) << "DeathHandler::serviceDied -- service unexpectedly died!"; @@ -164,7 +159,7 @@ static std::pair<int, std::shared_ptr<VersionedIPreparedModel>> makeVersionedIPr // proactively handle service crashes. If the linkToDeath call fails, // asynchronous calls are susceptible to hangs if the service crashes before // providing the response. - const Return<bool> ret = preparedModel->linkToDeath(deathHandler, 0); + const hardware::Return<bool> ret = preparedModel->linkToDeath(deathHandler, 0); if (ret.isDeadObject()) { LOG(ERROR) << "makeVersionedIPreparedModel failed to register a death recipient for the " "IPreparedModel object because the IPreparedModel object is dead."; @@ -206,10 +201,10 @@ std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::execu const Request& request, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration) const { const auto failDeadObject = []() -> std::tuple<int, std::vector<OutputShape>, Timing> { - return {ANEURALNETWORKS_DEAD_OBJECT, {}, kNoTiming}; + return {ANEURALNETWORKS_DEAD_OBJECT, {}, {}}; }; - const auto failWithStatus = [](ErrorStatus status) { - return getExecutionResult(status, {}, kNoTiming); + const auto failWithStatus = [](V1_3::ErrorStatus status) { + return getExecutionResult(status, {}, {}); }; const auto getResults = [failDeadObject](const ExecutionCallback& cb) { if (cb.isDeadObject()) { @@ -221,21 +216,23 @@ std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::execu const sp<ExecutionCallback> callback = new ExecutionCallback(); const auto scoped = mDeathHandler->protectCallback(callback); - // version 1.3+ HAL + // version 1.3 HAL + const V1_3::Request request13 = convertToV1_3(request); if (mPreparedModelV1_3 != nullptr) { const auto otp = makeTimePoint(deadline); - Return<ErrorStatus> ret = mPreparedModelV1_3->execute_1_3(request, measure, otp, - loopTimeoutDuration, callback); + hardware::Return<V1_3::ErrorStatus> ret = mPreparedModelV1_3->execute_1_3( + request13, convertToV1_2(measure), convertToV1_3(otp), + convertToV1_3(loopTimeoutDuration), callback); if (ret.isDeadObject()) { LOG(ERROR) << "execute_1_3 failure: " << ret.description(); return failDeadObject(); } if (!ret.isOk()) { LOG(ERROR) << "execute_1_3 failure: " << ret.description(); - return failWithStatus(ErrorStatus::GENERAL_FAILURE); + return failWithStatus(V1_3::ErrorStatus::GENERAL_FAILURE); } - if (ret != ErrorStatus::NONE) { - LOG(ERROR) << "execute_1_3 returned " << toString(static_cast<ErrorStatus>(ret)); + if (ret != V1_3::ErrorStatus::NONE) { + LOG(ERROR) << "execute_1_3 returned " << toString(static_cast<V1_3::ErrorStatus>(ret)); return failWithStatus(ret); } callback->wait(); @@ -244,21 +241,21 @@ std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::execu // version 1.2 HAL if (mPreparedModelV1_2 != nullptr) { - const bool compliant = compliantWithV1_2(request); + const bool compliant = compliantWithV1_2(request13); if (!compliant) { LOG(ERROR) << "Could not handle execute_1_2!"; - return failWithStatus(ErrorStatus::GENERAL_FAILURE); + return failWithStatus(V1_3::ErrorStatus::GENERAL_FAILURE); } - const V1_0::Request request12 = convertToV1_2(request); - Return<V1_0::ErrorStatus> ret = - mPreparedModelV1_2->execute_1_2(request12, measure, callback); + const V1_0::Request request12 = convertToV1_2(request13); + hardware::Return<V1_0::ErrorStatus> ret = + mPreparedModelV1_2->execute_1_2(request12, convertToV1_2(measure), callback); if (ret.isDeadObject()) { LOG(ERROR) << "execute_1_2 failure: " << ret.description(); return failDeadObject(); } if (!ret.isOk()) { LOG(ERROR) << "execute_1_2 failure: " << ret.description(); - return failWithStatus(ErrorStatus::GENERAL_FAILURE); + return failWithStatus(V1_3::ErrorStatus::GENERAL_FAILURE); } const V1_0::ErrorStatus status = static_cast<V1_0::ErrorStatus>(ret); if (status != V1_0::ErrorStatus::NONE) { @@ -271,20 +268,20 @@ std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::execu // version 1.0 HAL if (mPreparedModelV1_0 != nullptr) { - const bool compliant = compliantWithV1_0(request); + const bool compliant = compliantWithV1_0(request13); if (!compliant) { LOG(ERROR) << "Could not handle execute!"; - return failWithStatus(ErrorStatus::GENERAL_FAILURE); + return failWithStatus(V1_3::ErrorStatus::GENERAL_FAILURE); } - const V1_0::Request request10 = convertToV1_0(request); - Return<V1_0::ErrorStatus> ret = mPreparedModelV1_0->execute(request10, callback); + const V1_0::Request request10 = convertToV1_0(request13); + hardware::Return<V1_0::ErrorStatus> ret = mPreparedModelV1_0->execute(request10, callback); if (ret.isDeadObject()) { LOG(ERROR) << "execute failure: " << ret.description(); return failDeadObject(); } if (!ret.isOk()) { LOG(ERROR) << "execute failure: " << ret.description(); - return failWithStatus(ErrorStatus::GENERAL_FAILURE); + return failWithStatus(V1_3::ErrorStatus::GENERAL_FAILURE); } const V1_0::ErrorStatus status = static_cast<V1_0::ErrorStatus>(ret); if (status != V1_0::ErrorStatus::NONE) { @@ -297,24 +294,27 @@ std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::execu // No prepared model available LOG(ERROR) << "executeAsynchronously called with no preparedModel"; - return failWithStatus(ErrorStatus::GENERAL_FAILURE); + return failWithStatus(V1_3::ErrorStatus::GENERAL_FAILURE); } std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::executeSynchronously( const Request& request, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration) const { const std::tuple<int, std::vector<OutputShape>, Timing> kDeadObject = { - ANEURALNETWORKS_DEAD_OBJECT, {}, kNoTiming}; - const auto kFailure = getExecutionResult(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + ANEURALNETWORKS_DEAD_OBJECT, {}, {}}; + const auto kFailure = getExecutionResult(ErrorStatus::GENERAL_FAILURE, {}, {}); - // version 1.3+ HAL + // version 1.3 HAL + const V1_3::Request request13 = convertToV1_3(request); if (mPreparedModelV1_3 != nullptr) { std::tuple<int, std::vector<OutputShape>, Timing> result; const auto otp = makeTimePoint(deadline); - Return<void> ret = mPreparedModelV1_3->executeSynchronously_1_3( - request, measure, otp, loopTimeoutDuration, - [&result](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, - const Timing& timing) { + hardware::Return<void> ret = mPreparedModelV1_3->executeSynchronously_1_3( + request13, convertToV1_2(measure), convertToV1_3(otp), + convertToV1_3(loopTimeoutDuration), + [&result](V1_3::ErrorStatus error, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { result = getExecutionResult(error, outputShapes, timing); }); if (ret.isDeadObject()) { @@ -330,18 +330,19 @@ std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::execu // version 1.2 HAL if (mPreparedModelV1_2 != nullptr) { - const bool compliant = compliantWithV1_2(request); + const bool compliant = compliantWithV1_2(request13); if (!compliant) { LOG(ERROR) << "Could not handle executeSynchronously!"; return kFailure; } - const V1_0::Request request12 = convertToV1_2(request); + const V1_0::Request request12 = convertToV1_2(request13); std::tuple<int, std::vector<OutputShape>, Timing> result; - Return<void> ret = mPreparedModelV1_2->executeSynchronously( - request12, measure, - [&result](V1_0::ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, - const Timing& timing) { + hardware::Return<void> ret = mPreparedModelV1_2->executeSynchronously( + request12, convertToV1_2(measure), + [&result](V1_0::ErrorStatus error, + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { result = getExecutionResult(convertToV1_3(error), outputShapes, timing); }); if (ret.isDeadObject()) { @@ -363,11 +364,11 @@ std::tuple<int, std::vector<OutputShape>, Timing> VersionedIPreparedModel::execu const Request& request, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration, bool preferSynchronous) const { if (preferSynchronous) { - VLOG(EXECUTION) << "Before executeSynchronously() " << SHOW_IF_DEBUG(toString(request)); + VLOG(EXECUTION) << "Before executeSynchronously() " << SHOW_IF_DEBUG(request); return executeSynchronously(request, measure, deadline, loopTimeoutDuration); } - VLOG(EXECUTION) << "Before executeAsynchronously() " << SHOW_IF_DEBUG(toString(request)); + VLOG(EXECUTION) << "Before executeAsynchronously() " << SHOW_IF_DEBUG(request); return executeAsynchronously(request, measure, deadline, loopTimeoutDuration); } @@ -397,13 +398,15 @@ std::shared_ptr<ExecutionBurstController> VersionedIPreparedModel::configureExec return ExecutionBurstController::create(mPreparedModelV1_2, pollingTimeWindow); } -static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_3::IDevice* device) { +static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction( + V1_3::IDevice* device) { CHECK(device != nullptr); NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getCapabilities_1_3"); - const std::pair<ErrorStatus, Capabilities> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; - std::pair<ErrorStatus, Capabilities> result = kFailure; - const Return<void> ret = device->getCapabilities_1_3( - [&result](ErrorStatus error, const Capabilities& capabilities) { + const std::pair<V1_3::ErrorStatus, V1_3::Capabilities> kFailure = { + V1_3::ErrorStatus::GENERAL_FAILURE, {}}; + std::pair<V1_3::ErrorStatus, V1_3::Capabilities> result = kFailure; + const hardware::Return<void> ret = device->getCapabilities_1_3( + [&result](V1_3::ErrorStatus error, const V1_3::Capabilities& capabilities) { result = std::make_pair(error, capabilities); }); if (!ret.isOk()) { @@ -413,38 +416,39 @@ static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_3::IDevic return result; } -std::tuple<int, hal::hidl_handle, sp<hal::IFencedExecutionCallback>, hal::Timing> -VersionedIPreparedModel::executeFenced( - const hal::Request& request, const hal::hidl_vec<hal::hidl_handle>& waitFor, - MeasureTiming measure, const std::optional<Deadline>& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& timeoutDurationAfterFence) { - // version 1.3+ HAL - hal::hidl_handle syncFence; - sp<hal::IFencedExecutionCallback> dispatchCallback; - hal::Timing timing = {UINT64_MAX, UINT64_MAX}; +std::tuple<int, hardware::hidl_handle, sp<V1_3::IFencedExecutionCallback>, Timing> +VersionedIPreparedModel::executeFenced(const Request& request, + const hardware::hidl_vec<hardware::hidl_handle>& waitFor, + MeasureTiming measure, + const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + const OptionalTimeoutDuration& timeoutDurationAfterFence) { + // version 1.3 HAL + hardware::hidl_handle syncFence; + sp<V1_3::IFencedExecutionCallback> dispatchCallback; + Timing timing = {UINT64_MAX, UINT64_MAX}; if (mPreparedModelV1_3 != nullptr) { ErrorStatus errorStatus; const auto otp = makeTimePoint(deadline); - Return<void> ret = mPreparedModelV1_3->executeFenced( - request, waitFor, measure, otp, loopTimeoutDuration, timeoutDurationAfterFence, + hardware::Return<void> ret = mPreparedModelV1_3->executeFenced( + convertToV1_3(request), waitFor, convertToV1_2(measure), convertToV1_3(otp), + convertToV1_3(loopTimeoutDuration), convertToV1_3(timeoutDurationAfterFence), [&syncFence, &errorStatus, &dispatchCallback]( - ErrorStatus error, const hidl_handle& handle, - const sp<hal::IFencedExecutionCallback>& callback) { + V1_3::ErrorStatus error, const hardware::hidl_handle& handle, + const sp<V1_3::IFencedExecutionCallback>& callback) { syncFence = handle; - errorStatus = error; + errorStatus = uncheckedConvert(error); dispatchCallback = callback; }); if (!ret.isOk()) { LOG(ERROR) << "executeFenced failure: " << ret.description(); - return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hal::hidl_handle(nullptr), nullptr, - timing); + return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hardware::hidl_handle(nullptr), + nullptr, timing); } if (errorStatus != ErrorStatus::NONE) { - LOG(ERROR) << "executeFenced returned " - << toString(static_cast<ErrorStatus>(errorStatus)); + LOG(ERROR) << "executeFenced returned " << errorStatus; return std::make_tuple(convertErrorStatusToResultCode(errorStatus), - hal::hidl_handle(nullptr), nullptr, timing); + hardware::hidl_handle(nullptr), nullptr, timing); } return std::make_tuple(ANEURALNETWORKS_NO_ERROR, syncFence, dispatchCallback, timing); } @@ -454,33 +458,35 @@ VersionedIPreparedModel::executeFenced( LOG(INFO) << "No drivers able to handle sync fences, falling back to regular execution"; for (const auto& fenceHandle : waitFor) { if (!fenceHandle.getNativeHandle()) { - return std::make_tuple(ANEURALNETWORKS_BAD_DATA, hal::hidl_handle(nullptr), nullptr, - timing); + return std::make_tuple(ANEURALNETWORKS_BAD_DATA, hardware::hidl_handle(nullptr), + nullptr, timing); } int syncFd = fenceHandle.getNativeHandle()->data[0]; if (syncFd <= 0) { - return std::make_tuple(ANEURALNETWORKS_BAD_DATA, hal::hidl_handle(nullptr), nullptr, - timing); + return std::make_tuple(ANEURALNETWORKS_BAD_DATA, hardware::hidl_handle(nullptr), + nullptr, timing); } auto r = syncWait(syncFd, -1); if (r != FenceState::SIGNALED) { LOG(ERROR) << "syncWait failed, fd: " << syncFd; - return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hal::hidl_handle(nullptr), nullptr, - timing); + return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hardware::hidl_handle(nullptr), + nullptr, timing); } } int errorCode; std::tie(errorCode, std::ignore, timing) = executeSynchronously(request, measure, deadline, loopTimeoutDuration); - return std::make_tuple(errorCode, hal::hidl_handle(nullptr), nullptr, timing); + return std::make_tuple(errorCode, hardware::hidl_handle(nullptr), nullptr, timing); } -static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_2::IDevice* device) { +static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction( + V1_2::IDevice* device) { CHECK(device != nullptr); NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getCapabilities_1_2"); - const std::pair<ErrorStatus, Capabilities> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; - std::pair<ErrorStatus, Capabilities> result = kFailure; - const Return<void> ret = device->getCapabilities_1_2( + const std::pair<V1_3::ErrorStatus, V1_3::Capabilities> kFailure = { + V1_3::ErrorStatus::GENERAL_FAILURE, {}}; + std::pair<V1_3::ErrorStatus, V1_3::Capabilities> result = kFailure; + const hardware::Return<void> ret = device->getCapabilities_1_2( [&result](V1_0::ErrorStatus error, const V1_2::Capabilities& capabilities) { result = std::make_pair(convertToV1_3(error), convertToV1_3(capabilities)); }); @@ -491,12 +497,14 @@ static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_2::IDevic return result; } -static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_1::IDevice* device) { +static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction( + V1_1::IDevice* device) { CHECK(device != nullptr); NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getCapabilities_1_1"); - const std::pair<ErrorStatus, Capabilities> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; - std::pair<ErrorStatus, Capabilities> result = kFailure; - const Return<void> ret = device->getCapabilities_1_1( + const std::pair<V1_3::ErrorStatus, V1_3::Capabilities> kFailure = { + V1_3::ErrorStatus::GENERAL_FAILURE, {}}; + std::pair<V1_3::ErrorStatus, V1_3::Capabilities> result = kFailure; + const hardware::Return<void> ret = device->getCapabilities_1_1( [&result](V1_0::ErrorStatus error, const V1_1::Capabilities& capabilities) { // Time taken to convert capabilities is trivial result = std::make_pair(convertToV1_3(error), convertToV1_3(capabilities)); @@ -508,12 +516,14 @@ static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_1::IDevic return result; } -static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_0::IDevice* device) { +static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction( + V1_0::IDevice* device) { CHECK(device != nullptr); NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getCapabilities"); - const std::pair<ErrorStatus, Capabilities> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; - std::pair<ErrorStatus, Capabilities> result = kFailure; - const Return<void> ret = device->getCapabilities( + const std::pair<V1_3::ErrorStatus, V1_3::Capabilities> kFailure = { + V1_3::ErrorStatus::GENERAL_FAILURE, {}}; + std::pair<V1_3::ErrorStatus, V1_3::Capabilities> result = kFailure; + const hardware::Return<void> ret = device->getCapabilities( [&result](V1_0::ErrorStatus error, const V1_0::Capabilities& capabilities) { // Time taken to convert capabilities is trivial result = std::make_pair(convertToV1_3(error), convertToV1_3(capabilities)); @@ -525,14 +535,16 @@ static std::pair<ErrorStatus, Capabilities> getCapabilitiesFunction(V1_0::IDevic return result; } -static std::pair<ErrorStatus, hidl_vec<Extension>> getSupportedExtensionsFunction( - V1_2::IDevice* device) { +static std::pair<V1_3::ErrorStatus, hardware::hidl_vec<V1_2::Extension>> +getSupportedExtensionsFunction(V1_2::IDevice* device) { CHECK(device != nullptr); NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getSupportedExtensions"); - const std::pair<ErrorStatus, hidl_vec<Extension>> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; - std::pair<ErrorStatus, hidl_vec<Extension>> result = kFailure; - const Return<void> ret = device->getSupportedExtensions( - [&result](V1_0::ErrorStatus error, const hidl_vec<Extension>& extensions) { + const std::pair<V1_3::ErrorStatus, hardware::hidl_vec<V1_2::Extension>> kFailure = { + V1_3::ErrorStatus::GENERAL_FAILURE, {}}; + std::pair<V1_3::ErrorStatus, hardware::hidl_vec<V1_2::Extension>> result = kFailure; + const hardware::Return<void> ret = device->getSupportedExtensions( + [&result](V1_0::ErrorStatus error, + const hardware::hidl_vec<V1_2::Extension>& extensions) { result = std::make_pair(convertToV1_3(error), extensions); }); if (!ret.isOk()) { @@ -542,18 +554,18 @@ static std::pair<ErrorStatus, hidl_vec<Extension>> getSupportedExtensionsFunctio return result; } -static std::pair<ErrorStatus, hidl_vec<Extension>> getSupportedExtensionsFunction( - V1_0::IDevice* device) { +static std::pair<V1_3::ErrorStatus, hardware::hidl_vec<V1_2::Extension>> +getSupportedExtensionsFunction(V1_0::IDevice* device) { CHECK(device != nullptr); - return {ErrorStatus::NONE, {/* No extensions. */}}; + return {V1_3::ErrorStatus::NONE, {/* No extensions. */}}; } static int32_t getTypeFunction(V1_2::IDevice* device) { CHECK(device != nullptr); constexpr int32_t kFailure = -1; int32_t result = kFailure; - const Return<void> ret = - device->getType([&result](V1_0::ErrorStatus error, DeviceType deviceType) { + const hardware::Return<void> ret = + device->getType([&result](V1_0::ErrorStatus error, V1_2::DeviceType deviceType) { if (error == V1_0::ErrorStatus::NONE) { result = static_cast<int32_t>(deviceType); } @@ -570,12 +582,14 @@ static int32_t getTypeFunction(V1_0::IDevice* device) { return ANEURALNETWORKS_DEVICE_UNKNOWN; } -static std::pair<ErrorStatus, hidl_string> getVersionStringFunction(V1_2::IDevice* device) { +static std::pair<V1_3::ErrorStatus, hardware::hidl_string> getVersionStringFunction( + V1_2::IDevice* device) { CHECK(device != nullptr); - const std::pair<ErrorStatus, hidl_string> kFailure = {ErrorStatus::GENERAL_FAILURE, ""}; - std::pair<ErrorStatus, hidl_string> result = kFailure; - const Return<void> ret = device->getVersionString( - [&result](V1_0::ErrorStatus error, const hidl_string& version) { + const std::pair<V1_3::ErrorStatus, hardware::hidl_string> kFailure = { + V1_3::ErrorStatus::GENERAL_FAILURE, ""}; + std::pair<V1_3::ErrorStatus, hardware::hidl_string> result = kFailure; + const hardware::Return<void> ret = device->getVersionString( + [&result](V1_0::ErrorStatus error, const hardware::hidl_string& version) { result = std::make_pair(convertToV1_3(error), version); }); if (!ret.isOk()) { @@ -585,18 +599,19 @@ static std::pair<ErrorStatus, hidl_string> getVersionStringFunction(V1_2::IDevic return result; } -static std::pair<ErrorStatus, hidl_string> getVersionStringFunction(V1_0::IDevice* device) { +static std::pair<V1_3::ErrorStatus, hardware::hidl_string> getVersionStringFunction( + V1_0::IDevice* device) { CHECK(device != nullptr); - return {ErrorStatus::NONE, "UNKNOWN"}; + return {V1_3::ErrorStatus::NONE, "UNKNOWN"}; } -static std::tuple<ErrorStatus, uint32_t, uint32_t> getNumberOfCacheFilesNeededFunction( +static std::tuple<V1_3::ErrorStatus, uint32_t, uint32_t> getNumberOfCacheFilesNeededFunction( V1_2::IDevice* device) { CHECK(device != nullptr); - constexpr std::tuple<ErrorStatus, uint32_t, uint32_t> kFailure = {ErrorStatus::GENERAL_FAILURE, - 0, 0}; - std::tuple<ErrorStatus, uint32_t, uint32_t> result = kFailure; - const Return<void> ret = device->getNumberOfCacheFilesNeeded( + constexpr std::tuple<V1_3::ErrorStatus, uint32_t, uint32_t> kFailure = { + V1_3::ErrorStatus::GENERAL_FAILURE, 0, 0}; + std::tuple<V1_3::ErrorStatus, uint32_t, uint32_t> result = kFailure; + const hardware::Return<void> ret = device->getNumberOfCacheFilesNeeded( [&result](V1_0::ErrorStatus error, uint32_t numModelCache, uint32_t numDataCache) { result = {convertToV1_3(error), numModelCache, numDataCache}; }); @@ -607,17 +622,17 @@ static std::tuple<ErrorStatus, uint32_t, uint32_t> getNumberOfCacheFilesNeededFu return result; } -static std::tuple<ErrorStatus, uint32_t, uint32_t> getNumberOfCacheFilesNeededFunction( +static std::tuple<V1_3::ErrorStatus, uint32_t, uint32_t> getNumberOfCacheFilesNeededFunction( V1_0::IDevice* device) { CHECK(device != nullptr); - return {ErrorStatus::NONE, 0, 0}; + return {V1_3::ErrorStatus::NONE, 0, 0}; } struct InitialData { - hal::Capabilities capabilities; - hal::hidl_vec<hal::Extension> supportedExtensions; + V1_3::Capabilities capabilities; + hardware::hidl_vec<V1_2::Extension> supportedExtensions; int32_t type; - hal::hidl_string versionString; + hardware::hidl_string versionString; std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded; }; @@ -626,7 +641,7 @@ static std::optional<InitialData> initializeFunction(Device* device) { CHECK(device != nullptr); auto [capabilitiesStatus, capabilities] = getCapabilitiesFunction(device); - if (capabilitiesStatus != ErrorStatus::NONE) { + if (capabilitiesStatus != V1_3::ErrorStatus::NONE) { LOG(ERROR) << "IDevice::getCapabilities* returned the error " << toString(capabilitiesStatus); return std::nullopt; @@ -634,7 +649,7 @@ static std::optional<InitialData> initializeFunction(Device* device) { VLOG(MANAGER) << "Capab " << toString(capabilities); auto [versionStatus, versionString] = getVersionStringFunction(device); - if (versionStatus != ErrorStatus::NONE) { + if (versionStatus != V1_3::ErrorStatus::NONE) { LOG(ERROR) << "IDevice::getVersionString returned the error " << toString(versionStatus); return std::nullopt; } @@ -647,7 +662,7 @@ static std::optional<InitialData> initializeFunction(Device* device) { } auto [extensionsStatus, supportedExtensions] = getSupportedExtensionsFunction(device); - if (extensionsStatus != ErrorStatus::NONE) { + if (extensionsStatus != V1_3::ErrorStatus::NONE) { LOG(ERROR) << "IDevice::getSupportedExtensions returned the error " << toString(extensionsStatus); return std::nullopt; @@ -655,7 +670,7 @@ static std::optional<InitialData> initializeFunction(Device* device) { const auto [cacheFilesStatus, numModelCacheFiles, numDataCacheFiles] = getNumberOfCacheFilesNeededFunction(device); - if (cacheFilesStatus != ErrorStatus::NONE) { + if (cacheFilesStatus != V1_3::ErrorStatus::NONE) { LOG(ERROR) << "IDevice::getNumberOfCacheFilesNeeded returned the error " << toString(cacheFilesStatus); return std::nullopt; @@ -663,7 +678,7 @@ static std::optional<InitialData> initializeFunction(Device* device) { // The following limit is enforced by VTS constexpr uint32_t maxNumCacheFiles = - static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES); + static_cast<uint32_t>(V1_2::Constant::MAX_NUMBER_OF_CACHE_FILES); if (numModelCacheFiles > maxNumCacheFiles || numDataCacheFiles > maxNumCacheFiles) { LOG(ERROR) << "IDevice::getNumberOfCacheFilesNeeded returned invalid number of cache files: " @@ -684,7 +699,7 @@ static std::optional<InitialData> initializeFunction(Device* device) { template <typename Core> std::optional<InitialData> initialize(const Core& core) { - // version 1.3+ HAL + // version 1.3 HAL if (const auto device = core.template getDevice<V1_3::IDevice>()) { return initializeFunction(device.get()); } @@ -710,7 +725,7 @@ std::optional<InitialData> initialize(const Core& core) { } std::shared_ptr<VersionedIDevice> VersionedIDevice::create(std::string serviceName, - const DeviceFactory& makeDevice) { + const HalDeviceFactory& makeDevice) { CHECK(makeDevice != nullptr) << "VersionedIDevice::create passed invalid device factory object."; @@ -736,15 +751,16 @@ std::shared_ptr<VersionedIDevice> VersionedIDevice::create(std::string serviceNa auto [capabilities, supportedExtensions, type, versionString, numberOfCacheFilesNeeded] = std::move(*initialData); return std::make_shared<VersionedIDevice>( - std::move(capabilities), std::move(supportedExtensions), type, std::move(versionString), - numberOfCacheFilesNeeded, std::move(serviceName), makeDevice, std::move(core.value())); + uncheckedConvert(capabilities), uncheckedConvert(supportedExtensions), type, + std::move(versionString), numberOfCacheFilesNeeded, std::move(serviceName), makeDevice, + std::move(core.value())); } -VersionedIDevice::VersionedIDevice(hal::Capabilities capabilities, - std::vector<hal::Extension> supportedExtensions, int32_t type, +VersionedIDevice::VersionedIDevice(Capabilities capabilities, + std::vector<Extension> supportedExtensions, int32_t type, std::string versionString, std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded, - std::string serviceName, const DeviceFactory& makeDevice, + std::string serviceName, const HalDeviceFactory& makeDevice, Core core) : kCapabilities(std::move(capabilities)), kSupportedExtensions(std::move(supportedExtensions)), @@ -765,7 +781,7 @@ std::optional<VersionedIDevice::Core> VersionedIDevice::Core::create(sp<V1_0::ID // proactively handle service crashes. If the linkToDeath call fails, // asynchronous calls are susceptible to hangs if the service crashes before // providing the response. - const Return<bool> ret = device->linkToDeath(deathHandler, 0); + const hardware::Return<bool> ret = device->linkToDeath(deathHandler, 0); if (!ret.isOk()) { LOG(ERROR) << "VersionedIDevice::Core::create failed to register a death recipient for the " "IDevice object because of failure: " @@ -828,12 +844,13 @@ std::pair<sp<T_IDevice>, sp<IDeviceDeathHandler>> VersionedIDevice::Core::getDev } template <typename T_Return, typename T_IDevice, typename T_Callback> -Return<T_Return> callProtected(const char* context, - const std::function<Return<T_Return>(const sp<T_IDevice>&)>& fn, - const sp<T_IDevice>& device, const sp<T_Callback>& callback, - const sp<IDeviceDeathHandler>& deathHandler) { +hardware::Return<T_Return> callProtected( + const char* context, + const std::function<hardware::Return<T_Return>(const sp<T_IDevice>&)>& fn, + const sp<T_IDevice>& device, const sp<T_Callback>& callback, + const sp<IDeviceDeathHandler>& deathHandler) { const auto scoped = deathHandler->protectCallback(callback); - Return<T_Return> ret = fn(device); + hardware::Return<T_Return> ret = fn(device); // Suppose there was a transport error. We have the following cases: // 1. Either not due to a dead device, or due to a device that was // already dead at the time of the call to protectCallback(). In @@ -863,16 +880,16 @@ Return<T_Return> callProtected(const char* context, return ret; } template <typename T_Return, typename T_IDevice> -Return<T_Return> callProtected(const char*, - const std::function<Return<T_Return>(const sp<T_IDevice>&)>& fn, - const sp<T_IDevice>& device, const std::nullptr_t&, - const sp<IDeviceDeathHandler>&) { +hardware::Return<T_Return> callProtected( + const char*, const std::function<hardware::Return<T_Return>(const sp<T_IDevice>&)>& fn, + const sp<T_IDevice>& device, const std::nullptr_t&, const sp<IDeviceDeathHandler>&) { return fn(device); } template <typename T_Return, typename T_IDevice, typename T_Callback> -Return<T_Return> VersionedIDevice::recoverable( - const char* context, const std::function<Return<T_Return>(const sp<T_IDevice>&)>& fn, +hardware::Return<T_Return> VersionedIDevice::recoverable( + const char* context, + const std::function<hardware::Return<T_Return>(const sp<T_IDevice>&)>& fn, const T_Callback& callback) const EXCLUDES(mMutex) { CHECK_EQ(callback == nullptr, (std::is_same_v<T_Callback, std::nullptr_t>)); @@ -880,7 +897,7 @@ Return<T_Return> VersionedIDevice::recoverable( sp<IDeviceDeathHandler> deathHandler; std::tie(device, deathHandler) = getDeviceAndDeathHandler<T_IDevice>(); - Return<T_Return> ret = callProtected(context, fn, device, callback, deathHandler); + hardware::Return<T_Return> ret = callProtected(context, fn, device, callback, deathHandler); if (ret.isDeadObject()) { { @@ -958,42 +975,42 @@ const std::vector<Extension>& VersionedIDevice::getSupportedExtensions() const { return kSupportedExtensions; } -std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( +std::pair<ErrorStatus, std::vector<bool>> VersionedIDevice::getSupportedOperations( const MetaModel& metaModel) const { - const std::pair<ErrorStatus, hidl_vec<bool>> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; - std::pair<ErrorStatus, hidl_vec<bool>> result; + const std::pair<ErrorStatus, std::vector<bool>> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; + std::pair<ErrorStatus, std::vector<bool>> result; const Model& model = metaModel.getModel(); auto noneSupported = [&model] { - hidl_vec<bool> supported(model.main.operations.size()); - std::fill(supported.begin(), supported.end(), false); + std::vector<bool> supported(model.main.operations.size(), false); return std::make_pair(ErrorStatus::NONE, std::move(supported)); }; - auto remappedResult = [&model](const std::pair<ErrorStatus, hidl_vec<bool>>& result, - const std::function<uint32_t(uint32_t)>& - slicedModelOperationIndexToModelOperationIndex) { - const ErrorStatus status = result.first; - const hidl_vec<bool>& supported = result.second; - hidl_vec<bool> remappedSupported(model.main.operations.size()); - std::fill(remappedSupported.begin(), remappedSupported.end(), false); - for (size_t i = 0; i < supported.size(); ++i) { - if (supported[i]) { - remappedSupported[slicedModelOperationIndexToModelOperationIndex(i)] = true; - } - } - return std::make_pair(status, std::move(remappedSupported)); - }; + auto remappedResult = + [&model](const std::pair<ErrorStatus, std::vector<bool>>& result, + const MetaModel::Mapper& slicedModelOperationIndexToModelOperationIndex) { + const ErrorStatus status = result.first; + const std::vector<bool>& supported = result.second; + std::vector<bool> remappedSupported(model.main.operations.size(), false); + for (size_t i = 0; i < supported.size(); ++i) { + if (supported[i]) { + remappedSupported[slicedModelOperationIndexToModelOperationIndex(i)] = true; + } + } + return std::make_pair(status, std::move(remappedSupported)); + }; - // version 1.3+ HAL + // version 1.3 HAL + const V1_3::Model model13 = convertToV1_3(model); if (getDevice<V1_3::IDevice>() != nullptr) { NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "getSupportedOperations_1_3"); - Return<void> ret = recoverable<void, V1_3::IDevice>( - __FUNCTION__, [&model, &result](const sp<V1_3::IDevice>& device) { + hardware::Return<void> ret = recoverable<void, V1_3::IDevice>( + __FUNCTION__, [&model13, &result](const sp<V1_3::IDevice>& device) { return device->getSupportedOperations_1_3( - model, [&result](ErrorStatus error, const hidl_vec<bool>& supported) { - result = std::make_pair(error, supported); + model13, [&result](V1_3::ErrorStatus error, + const hardware::hidl_vec<bool>& supported) { + result = std::make_pair(uncheckedConvert(error), supported); }); }); if (!ret.isOk()) { @@ -1005,11 +1022,11 @@ std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( // version 1.2 HAL if (getDevice<V1_2::IDevice>() != nullptr) { - const bool compliant = compliantWithV1_2(model); + const bool compliant = compliantWithV1_2(model13); V1_2::Model model12; - std::function<uint32_t(uint32_t)> slicedModelOperationIndexToModelOperationIndex; + MetaModel::Mapper slicedModelOperationIndexToModelOperationIndex; if (compliant) { - model12 = convertToV1_2(model); + model12 = convertToV1_2(model13); } else { const auto slice12 = metaModel.getSliceV1_2(); if (!slice12.has_value()) { @@ -1018,12 +1035,12 @@ std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( std::tie(model12, slicedModelOperationIndexToModelOperationIndex) = *slice12; } NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "getSupportedOperations_1_2"); - Return<void> ret = recoverable<void, V1_2::IDevice>( + hardware::Return<void> ret = recoverable<void, V1_2::IDevice>( __FUNCTION__, [&model12, &result](const sp<V1_2::IDevice>& device) { return device->getSupportedOperations_1_2( - model12, - [&result](V1_0::ErrorStatus error, const hidl_vec<bool>& supported) { - result = std::make_pair(convertToV1_3(error), supported); + model12, [&result](V1_0::ErrorStatus error, + const hardware::hidl_vec<bool>& supported) { + result = std::make_pair(uncheckedConvert(error), supported); }); }); if (!ret.isOk()) { @@ -1038,11 +1055,11 @@ std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( // version 1.1 HAL if (getDevice<V1_1::IDevice>() != nullptr) { - const bool compliant = compliantWithV1_1(model); + const bool compliant = compliantWithV1_1(model13); V1_1::Model model11; - std::function<uint32_t(uint32_t)> slicedModelOperationIndexToModelOperationIndex; + MetaModel::Mapper slicedModelOperationIndexToModelOperationIndex; if (compliant) { - model11 = convertToV1_1(model); + model11 = convertToV1_1(model13); } else { const auto slice11 = metaModel.getSliceV1_1(); if (!slice11.has_value()) { @@ -1051,12 +1068,12 @@ std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( std::tie(model11, slicedModelOperationIndexToModelOperationIndex) = *slice11; } NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "getSupportedOperations_1_1"); - Return<void> ret = recoverable<void, V1_1::IDevice>( + hardware::Return<void> ret = recoverable<void, V1_1::IDevice>( __FUNCTION__, [&model11, &result](const sp<V1_1::IDevice>& device) { return device->getSupportedOperations_1_1( - model11, - [&result](V1_0::ErrorStatus error, const hidl_vec<bool>& supported) { - result = std::make_pair(convertToV1_3(error), supported); + model11, [&result](V1_0::ErrorStatus error, + const hardware::hidl_vec<bool>& supported) { + result = std::make_pair(uncheckedConvert(error), supported); }); }); if (!ret.isOk()) { @@ -1071,11 +1088,11 @@ std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( // version 1.0 HAL if (getDevice<V1_0::IDevice>() != nullptr) { - const bool compliant = compliantWithV1_0(model); + const bool compliant = compliantWithV1_0(model13); V1_0::Model model10; - std::function<uint32_t(uint32_t)> slicedModelOperationIndexToModelOperationIndex; + MetaModel::Mapper slicedModelOperationIndexToModelOperationIndex; if (compliant) { - model10 = convertToV1_0(model); + model10 = convertToV1_0(model13); } else { const auto slice10 = metaModel.getSliceV1_0(); if (!slice10.has_value()) { @@ -1084,12 +1101,12 @@ std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( std::tie(model10, slicedModelOperationIndexToModelOperationIndex) = *slice10; } NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "getSupportedOperations"); - Return<void> ret = recoverable<void, V1_0::IDevice>( + hardware::Return<void> ret = recoverable<void, V1_0::IDevice>( __FUNCTION__, [&model10, &result](const sp<V1_0::IDevice>& device) { return device->getSupportedOperations( - model10, - [&result](V1_0::ErrorStatus error, const hidl_vec<bool>& supported) { - result = std::make_pair(convertToV1_3(error), supported); + model10, [&result](V1_0::ErrorStatus error, + const hardware::hidl_vec<bool>& supported) { + result = std::make_pair(uncheckedConvert(error), supported); }); }); if (!ret.isOk()) { @@ -1111,7 +1128,7 @@ std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( // handle is expected to come in as empty, and is only set to a fd when the function returns true. // The file descriptor is always opened with both read and write permission. static bool createCacheHandle(const std::string& cache, bool createIfNotExist, - hidl_handle* handle) { + hardware::hidl_handle* handle) { CHECK(handle->getNativeHandle() == nullptr); int fd = open(cache.c_str(), createIfNotExist ? (O_RDWR | O_CREAT) : O_RDWR, S_IRUSR | S_IWUSR); NN_RET_CHECK_GE(fd, 0); @@ -1127,16 +1144,15 @@ static bool createCacheHandle(const std::string& cache, bool createIfNotExist, // Opens a list of cache files and returns the handle vector. Returns empty vector on fail. // The file descriptors are always opened with both read and write permission. -static hidl_vec<hidl_handle> createCacheHandleVec(uint32_t numCacheFiles, - const std::string& baseFileName, - bool createIfNotExist) { - CHECK(numCacheFiles <= static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES)); - hidl_vec<hidl_handle> handles(numCacheFiles); +static hardware::hidl_vec<hardware::hidl_handle> createCacheHandleVec( + uint32_t numCacheFiles, const std::string& baseFileName, bool createIfNotExist) { + CHECK(numCacheFiles <= static_cast<uint32_t>(V1_2::Constant::MAX_NUMBER_OF_CACHE_FILES)); + hardware::hidl_vec<hardware::hidl_handle> handles(numCacheFiles); for (uint32_t i = 0; i < numCacheFiles; i++) { std::string filename = baseFileName + std::to_string(i); VLOG(COMPILATION) << "Cache " << i << ": " << filename; if (!createCacheHandle(filename, createIfNotExist, &handles[i])) { - return hidl_vec<hidl_handle>(); + return hardware::hidl_vec<hardware::hidl_handle>(); } } return handles; @@ -1146,8 +1162,9 @@ static hidl_vec<hidl_handle> createCacheHandleVec(uint32_t numCacheFiles, // fail and leaves the vectors empty. Each vector is expected to come in as empty. static bool getCacheHandles(const std::string& cacheDir, const CacheToken& token, const std::pair<uint32_t, uint32_t>& numCacheFiles, - bool createIfNotExist, hidl_vec<hidl_handle>* modelCache, - hidl_vec<hidl_handle>* dataCache) { + bool createIfNotExist, + hardware::hidl_vec<hardware::hidl_handle>* modelCache, + hardware::hidl_vec<hardware::hidl_handle>* dataCache) { // The filename includes ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN * 2 characters for token, // and 1 character for model/data cache identifier. std::string filename(ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN * 2 + 1, '0'); @@ -1193,7 +1210,7 @@ static std::pair<int, std::shared_ptr<VersionedIPreparedModel>> prepareModelResu if (status != ErrorStatus::NONE) { LOG(ERROR) << prepareName << " on " << serviceName << " failed: " - << "prepareReturnStatus=" << toString(status); + << "prepareReturnStatus=" << status; return prepareModelFailure(status); } if (preparedModel == nullptr) { @@ -1214,7 +1231,7 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa ANEURALNETWORKS_DEAD_OBJECT, nullptr}; // Get cache files if they exist, otherwise create them. - hidl_vec<hidl_handle> modelCache, dataCache; + hardware::hidl_vec<hardware::hidl_handle> modelCache, dataCache; if (!maybeToken.has_value() || !getCacheHandles(cacheDir, *maybeToken, kNumberOfCacheFilesNeeded, /*createIfNotExist=*/true, &modelCache, &dataCache)) { @@ -1226,19 +1243,22 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa static const CacheToken kNullToken{}; const CacheToken token = maybeToken.value_or(kNullToken); + const V1_3::Model model13 = convertToV1_3(model); const sp<PreparedModelCallback> callback = new PreparedModelCallback(); // If 1.3 device, try preparing model if (getDevice<V1_3::IDevice>() != nullptr) { const auto otp = makeTimePoint(deadline); - const Return<ErrorStatus> ret = recoverable<ErrorStatus, V1_3::IDevice>( - __FUNCTION__, - [&model, preference, priority, &otp, &modelCache, &dataCache, &token, - &callback](const sp<V1_3::IDevice>& device) { - return device->prepareModel_1_3(model, preference, priority, otp, modelCache, - dataCache, token, callback); - }, - callback); + const hardware::Return<V1_3::ErrorStatus> ret = + recoverable<V1_3::ErrorStatus, V1_3::IDevice>( + __FUNCTION__, + [&model13, preference, priority, &otp, &modelCache, &dataCache, &token, + &callback](const sp<V1_3::IDevice>& device) { + return device->prepareModel_1_3( + model13, convertToV1_1(preference), convertToV1_3(priority), + convertToV1_3(otp), modelCache, dataCache, token, callback); + }, + callback); if (ret.isDeadObject()) { LOG(ERROR) << "prepareModel_1_3 failure: " << ret.description(); return kDeadObject; @@ -1247,9 +1267,10 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa LOG(ERROR) << "prepareModel_1_3 failure: " << ret.description(); return prepareModelFailure(); } - if (ret != ErrorStatus::NONE) { - LOG(ERROR) << "prepareModel_1_3 returned " << toString(static_cast<ErrorStatus>(ret)); - return prepareModelFailure(ret); + const ErrorStatus status = uncheckedConvert(ret); + if (status != ErrorStatus::NONE) { + LOG(ERROR) << "prepareModel_1_3 returned " << status; + return prepareModelFailure(status); } return prepareModelResult(*callback, "prepareModel_1_3", kServiceName); } @@ -1264,20 +1285,22 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa // but could be larger for other models). NNTRACE_FULL_SUBTRACT(NNTRACE_LAYER_RUNTIME, NNTRACE_PHASE_COMPILATION, "VersionedIDevice::prepareModel_1_2"); - compliant = compliantWithV1_2(model); + compliant = compliantWithV1_2(model13); if (compliant) { - model12 = convertToV1_2(model); // copy is elided + model12 = convertToV1_2(model13); // copy is elided } } if (compliant) { - const Return<V1_0::ErrorStatus> ret = recoverable<V1_0::ErrorStatus, V1_2::IDevice>( - __FUNCTION__, - [&model12, &preference, &modelCache, &dataCache, &token, - &callback](const sp<V1_2::IDevice>& device) { - return device->prepareModel_1_2(model12, preference, modelCache, dataCache, - token, callback); - }, - callback); + const hardware::Return<V1_0::ErrorStatus> ret = + recoverable<V1_0::ErrorStatus, V1_2::IDevice>( + __FUNCTION__, + [&model12, &preference, &modelCache, &dataCache, &token, + &callback](const sp<V1_2::IDevice>& device) { + return device->prepareModel_1_2(model12, convertToV1_1(preference), + modelCache, dataCache, token, + callback); + }, + callback); if (ret.isDeadObject()) { LOG(ERROR) << "prepareModel_1_2 failure: " << ret.description(); return kDeadObject; @@ -1286,10 +1309,10 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa LOG(ERROR) << "prepareModel_1_2 failure: " << ret.description(); return prepareModelFailure(); } - const V1_0::ErrorStatus status = static_cast<V1_0::ErrorStatus>(ret); - if (status != V1_0::ErrorStatus::NONE) { - LOG(ERROR) << "prepareModel_1_2 returned " << toString(status); - return prepareModelFailure(convertToV1_3(status)); + const ErrorStatus status = uncheckedConvert(ret); + if (status != ErrorStatus::NONE) { + LOG(ERROR) << "prepareModel_1_2 returned " << status; + return prepareModelFailure(status); } return prepareModelResult(*callback, "prepareModel_1_2", kServiceName); } @@ -1308,18 +1331,20 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa // but could be larger for other models). NNTRACE_FULL_SUBTRACT(NNTRACE_LAYER_RUNTIME, NNTRACE_PHASE_COMPILATION, "VersionedIDevice::prepareModel_1_1"); - compliant = compliantWithV1_1(model); + compliant = compliantWithV1_1(model13); if (compliant) { - model11 = convertToV1_1(model); // copy is elided + model11 = convertToV1_1(model13); // copy is elided } } if (compliant) { - const Return<V1_0::ErrorStatus> ret = recoverable<V1_0::ErrorStatus, V1_1::IDevice>( - __FUNCTION__, - [&model11, &preference, &callback](const sp<V1_1::IDevice>& device) { - return device->prepareModel_1_1(model11, preference, callback); - }, - callback); + const hardware::Return<V1_0::ErrorStatus> ret = + recoverable<V1_0::ErrorStatus, V1_1::IDevice>( + __FUNCTION__, + [&model11, &preference, &callback](const sp<V1_1::IDevice>& device) { + return device->prepareModel_1_1(model11, convertToV1_1(preference), + callback); + }, + callback); if (ret.isDeadObject()) { LOG(ERROR) << "prepareModel_1_1 failure: " << ret.description(); return kDeadObject; @@ -1328,10 +1353,10 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa LOG(ERROR) << "prepareModel_1_1 failure: " << ret.description(); return prepareModelFailure(); } - const V1_0::ErrorStatus status = static_cast<V1_0::ErrorStatus>(ret); - if (status != V1_0::ErrorStatus::NONE) { - LOG(ERROR) << "prepareModel_1_1 returned " << toString(status); - return prepareModelFailure(convertToV1_3(status)); + const ErrorStatus status = uncheckedConvert(ret); + if (status != ErrorStatus::NONE) { + LOG(ERROR) << "prepareModel_1_1 returned " << status; + return prepareModelFailure(status); } return prepareModelResult(*callback, "prepareModel_1_1", kServiceName); } @@ -1350,18 +1375,19 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa // but could be larger for other models). NNTRACE_FULL_SUBTRACT(NNTRACE_LAYER_RUNTIME, NNTRACE_PHASE_COMPILATION, "VersionedIDevice::prepareModel"); - compliant = compliantWithV1_0(model); + compliant = compliantWithV1_0(model13); if (compliant) { - model10 = convertToV1_0(model); // copy is elided + model10 = convertToV1_0(model13); // copy is elided } } if (compliant) { - const Return<V1_0::ErrorStatus> ret = recoverable<V1_0::ErrorStatus, V1_0::IDevice>( - __FUNCTION__, - [&model10, &callback](const sp<V1_0::IDevice>& device) { - return device->prepareModel(model10, callback); - }, - callback); + const hardware::Return<V1_0::ErrorStatus> ret = + recoverable<V1_0::ErrorStatus, V1_0::IDevice>( + __FUNCTION__, + [&model10, &callback](const sp<V1_0::IDevice>& device) { + return device->prepareModel(model10, callback); + }, + callback); if (ret.isDeadObject()) { LOG(ERROR) << "prepareModel failure: " << ret.description(); return kDeadObject; @@ -1370,10 +1396,10 @@ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepa LOG(ERROR) << "prepareModel failure: " << ret.description(); return prepareModelFailure(); } - const V1_0::ErrorStatus status = static_cast<V1_0::ErrorStatus>(ret); - if (status != V1_0::ErrorStatus::NONE) { - LOG(ERROR) << "prepareModel returned " << toString(status); - return prepareModelFailure(convertToV1_3(status)); + const ErrorStatus status = uncheckedConvert(ret); + if (status != ErrorStatus::NONE) { + LOG(ERROR) << "prepareModel returned " << status; + return prepareModelFailure(status); } return prepareModelResult(*callback, "prepareModel", kServiceName); } @@ -1398,24 +1424,25 @@ VersionedIDevice::prepareModelFromCacheInternal(const std::optional<Deadline>& d ANEURALNETWORKS_DEAD_OBJECT, nullptr}; // Get cache files if they exist, otherwise return from the function early. - hidl_vec<hidl_handle> modelCache, dataCache; + hardware::hidl_vec<hardware::hidl_handle> modelCache, dataCache; if (!getCacheHandles(cacheDir, token, kNumberOfCacheFilesNeeded, /*createIfNotExist=*/false, &modelCache, &dataCache)) { return prepareModelFailure(); } - // version 1.3+ HAL + // version 1.3 HAL if (getDevice<V1_3::IDevice>() != nullptr) { const auto otp = makeTimePoint(deadline); const sp<PreparedModelCallback> callback = new PreparedModelCallback(); - const Return<ErrorStatus> ret = recoverable<ErrorStatus, V1_3::IDevice>( - __FUNCTION__, - [&otp, &modelCache, &dataCache, &token, - &callback](const sp<V1_3::IDevice>& device) { - return device->prepareModelFromCache_1_3(otp, modelCache, dataCache, token, - callback); - }, - callback); + const hardware::Return<V1_3::ErrorStatus> ret = + recoverable<V1_3::ErrorStatus, V1_3::IDevice>( + __FUNCTION__, + [&otp, &modelCache, &dataCache, &token, + &callback](const sp<V1_3::IDevice>& device) { + return device->prepareModelFromCache_1_3(convertToV1_3(otp), modelCache, + dataCache, token, callback); + }, + callback); if (ret.isDeadObject()) { LOG(ERROR) << "prepareModelFromCache_1_3 failure: " << ret.description(); return kDeadObject; @@ -1424,10 +1451,10 @@ VersionedIDevice::prepareModelFromCacheInternal(const std::optional<Deadline>& d LOG(ERROR) << "prepareModelFromCache_1_3 failure: " << ret.description(); return prepareModelFailure(); } - if (ret != ErrorStatus::NONE) { - LOG(ERROR) << "prepareModelFromCache_1_3 returned " - << toString(static_cast<ErrorStatus>(ret)); - return prepareModelFailure(ret); + const ErrorStatus status = uncheckedConvert(ret); + if (status != ErrorStatus::NONE) { + LOG(ERROR) << "prepareModelFromCache_1_3 returned " << status; + return prepareModelFailure(status); } return prepareModelResult(*callback, "prepareModelFromCache_1_3", kServiceName); } @@ -1435,12 +1462,15 @@ VersionedIDevice::prepareModelFromCacheInternal(const std::optional<Deadline>& d // version 1.2 HAL if (getDevice<V1_2::IDevice>() != nullptr) { const sp<PreparedModelCallback> callback = new PreparedModelCallback(); - const Return<V1_0::ErrorStatus> ret = recoverable<V1_0::ErrorStatus, V1_2::IDevice>( - __FUNCTION__, - [&modelCache, &dataCache, &token, &callback](const sp<V1_2::IDevice>& device) { - return device->prepareModelFromCache(modelCache, dataCache, token, callback); - }, - callback); + const hardware::Return<V1_0::ErrorStatus> ret = + recoverable<V1_0::ErrorStatus, V1_2::IDevice>( + __FUNCTION__, + [&modelCache, &dataCache, &token, + &callback](const sp<V1_2::IDevice>& device) { + return device->prepareModelFromCache(modelCache, dataCache, token, + callback); + }, + callback); if (ret.isDeadObject()) { LOG(ERROR) << "prepareModelFromCache failure: " << ret.description(); return kDeadObject; @@ -1449,10 +1479,10 @@ VersionedIDevice::prepareModelFromCacheInternal(const std::optional<Deadline>& d LOG(ERROR) << "prepareModelFromCache failure: " << ret.description(); return prepareModelFailure(); } - const V1_0::ErrorStatus status = static_cast<V1_0::ErrorStatus>(ret); - if (status != V1_0::ErrorStatus::NONE) { - LOG(ERROR) << "prepareModelFromCache returned " << toString(status); - return prepareModelFailure(convertToV1_3(status)); + const ErrorStatus status = uncheckedConvert(ret); + if (status != ErrorStatus::NONE) { + LOG(ERROR) << "prepareModelFromCache returned " << status; + return prepareModelFailure(status); } return prepareModelResult(*callback, "prepareModelFromCache", kServiceName); } @@ -1520,28 +1550,31 @@ const std::string& VersionedIDevice::getName() const { return kServiceName; } -std::tuple<ErrorStatus, sp<IBuffer>, uint32_t> VersionedIDevice::allocate( - const BufferDesc& desc, +std::tuple<V1_3::ErrorStatus, sp<V1_3::IBuffer>, uint32_t> VersionedIDevice::allocate( + const V1_3::BufferDesc& desc, const std::vector<std::shared_ptr<VersionedIPreparedModel>>& versionedPreparedModels, - const hidl_vec<BufferRole>& inputRoles, const hidl_vec<BufferRole>& outputRoles) const { - const auto kFailure = std::make_tuple<ErrorStatus, sp<IBuffer>, uint32_t>( - ErrorStatus::GENERAL_FAILURE, nullptr, 0); + const std::vector<BufferRole>& inputRoles, + const std::vector<BufferRole>& outputRoles) const { + const auto kFailure = std::make_tuple<V1_3::ErrorStatus, sp<V1_3::IBuffer>, uint32_t>( + V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, 0); - // version 1.3+ HAL + // version 1.3 HAL if (getDevice<V1_3::IDevice>() != nullptr) { - hidl_vec<sp<V1_3::IPreparedModel>> preparedModels(versionedPreparedModels.size()); + hardware::hidl_vec<sp<V1_3::IPreparedModel>> preparedModels(versionedPreparedModels.size()); std::transform(versionedPreparedModels.begin(), versionedPreparedModels.end(), preparedModels.begin(), [](const auto& preparedModel) { return preparedModel->getV1_3(); }); - std::tuple<ErrorStatus, sp<IBuffer>, int32_t> result; - const Return<void> ret = recoverable<void, V1_3::IDevice>( + std::tuple<V1_3::ErrorStatus, sp<V1_3::IBuffer>, int32_t> result; + const hardware::Return<void> ret = recoverable<void, V1_3::IDevice>( __FUNCTION__, [&](const sp<V1_3::IDevice>& device) { - return device->allocate(desc, preparedModels, inputRoles, outputRoles, - [&result](ErrorStatus error, const sp<IBuffer>& buffer, - uint32_t token) { - result = {error, buffer, token}; - }); + return device->allocate( + desc, preparedModels, convertToV1_3(inputRoles), + convertToV1_3(outputRoles), + [&result](V1_3::ErrorStatus error, const sp<V1_3::IBuffer>& buffer, + uint32_t token) { + result = {error, buffer, token}; + }); }); if (!ret.isOk()) { LOG(ERROR) << "allocate failure: " << ret.description(); diff --git a/nn/runtime/VersionedInterfaces.h b/nn/runtime/VersionedInterfaces.h index 1b8433e1c..d41dcd3ad 100644 --- a/nn/runtime/VersionedInterfaces.h +++ b/nn/runtime/VersionedInterfaces.h @@ -43,6 +43,8 @@ class IPreparedModelDeathHandler; class MetaModel; class VersionedIPreparedModel; +using ModelFactory = std::function<Model()>; + /** * Each class (VersionedIDevice, VersionedIPreparedModel) wraps a HIDL interface * of any version to abstract away version differences. It allows the remainder @@ -77,7 +79,7 @@ class VersionedIDevice { * @return A valid VersionedIDevice object, otherwise nullptr. */ static std::shared_ptr<VersionedIDevice> create(std::string serviceName, - const hal::DeviceFactory& makeDevice); + const HalDeviceFactory& makeDevice); /** * Constructor for the VersionedIDevice object. @@ -98,18 +100,17 @@ class VersionedIDevice { * newer interfaces, and a hidl_death_recipient that will proactively handle * the case when the service containing the IDevice object crashes. */ - VersionedIDevice(hal::Capabilities capabilities, - std::vector<hal::Extension> supportedExtensions, int32_t type, - std::string versionString, + VersionedIDevice(Capabilities capabilities, std::vector<Extension> supportedExtensions, + int32_t type, std::string versionString, std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded, - std::string serviceName, const hal::DeviceFactory& makeDevice, Core core); + std::string serviceName, const HalDeviceFactory& makeDevice, Core core); /** * Gets the capabilities of a driver. * * @return capabilities Capabilities of the driver. */ - const hal::Capabilities& getCapabilities() const; + const Capabilities& getCapabilities() const; /** * Gets information about extensions supported by the driver implementation. @@ -122,7 +123,7 @@ class VersionedIDevice { * * @return extensions A list of supported extensions. */ - const std::vector<hal::Extension>& getSupportedExtensions() const; + const std::vector<Extension>& getSupportedExtensions() const; /** * Gets the supported operations in a MetaModel. @@ -152,7 +153,7 @@ class VersionedIDevice { * corresponds with the index of the operation * it is describing. */ - std::pair<hal::ErrorStatus, hal::hidl_vec<bool>> getSupportedOperations( + std::pair<ErrorStatus, std::vector<bool>> getSupportedOperations( const MetaModel& metaModel) const; /** @@ -220,9 +221,9 @@ class VersionedIDevice { * that has been prepared for execution, else nullptr. */ std::pair<int, std::shared_ptr<VersionedIPreparedModel>> prepareModel( - const hal::ModelFactory& makeModel, hal::ExecutionPreference preference, hal::Priority, + const ModelFactory& makeModel, ExecutionPreference preference, Priority, const std::optional<Deadline>& deadline, const std::string& cacheDir, - const std::optional<hal::CacheToken>& maybeToken) const; + const std::optional<CacheToken>& maybeToken) const; /** * Returns the feature level of a driver. @@ -366,11 +367,11 @@ class VersionedIDevice { * execution. If the buffer was unable to be allocated due to an error, the token must be * 0. */ - std::tuple<hal::ErrorStatus, sp<hal::IBuffer>, uint32_t> allocate( - const hal::BufferDesc& desc, + std::tuple<V1_3::ErrorStatus, sp<V1_3::IBuffer>, uint32_t> allocate( + const V1_3::BufferDesc& desc, const std::vector<std::shared_ptr<VersionedIPreparedModel>>& preparedModels, - const hal::hidl_vec<hal::BufferRole>& inputRoles, - const hal::hidl_vec<hal::BufferRole>& outputRoles) const; + const std::vector<BufferRole>& inputRoles, + const std::vector<BufferRole>& outputRoles) const; /** * Blocks until the device is not in a bad state. @@ -382,20 +383,20 @@ class VersionedIDevice { private: // Cached initialization results. - const hal::Capabilities kCapabilities; - const std::vector<hal::Extension> kSupportedExtensions; + const Capabilities kCapabilities; + const std::vector<Extension> kSupportedExtensions; const int32_t kType; const std::string kVersionString; const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded; // internal methods to prepare a model std::pair<int, std::shared_ptr<VersionedIPreparedModel>> prepareModelInternal( - const hal::Model& model, hal::ExecutionPreference preference, hal::Priority priority, + const Model& model, ExecutionPreference preference, Priority priority, const std::optional<Deadline>& deadline, const std::string& cacheDir, - const std::optional<hal::CacheToken>& maybeToken) const; + const std::optional<CacheToken>& maybeToken) const; std::pair<int, std::shared_ptr<VersionedIPreparedModel>> prepareModelFromCacheInternal( const std::optional<Deadline>& deadline, const std::string& cacheDir, - const hal::CacheToken& token) const; + const CacheToken& token) const; /** * This is a utility class for VersionedIDevice that encapsulates a @@ -426,7 +427,7 @@ class VersionedIDevice { * the case when the service containing the IDevice * object crashes. */ - Core(sp<hal::V1_0::IDevice> device, sp<IDeviceDeathHandler> deathHandler); + Core(sp<V1_0::IDevice> device, sp<IDeviceDeathHandler> deathHandler); /** * Destructor for the Core object. @@ -456,7 +457,7 @@ class VersionedIDevice { * interface. * @return A valid Core object, otherwise nullopt. */ - static std::optional<Core> create(sp<hal::V1_0::IDevice> device); + static std::optional<Core> create(sp<V1_0::IDevice> device); /** * Returns sp<*::IDevice> that is a downcast of the sp<V1_0::IDevice> @@ -466,19 +467,19 @@ class VersionedIDevice { template <typename T_IDevice> sp<T_IDevice> getDevice() const; template <> - sp<hal::V1_0::IDevice> getDevice() const { + sp<V1_0::IDevice> getDevice() const { return mDeviceV1_0; } template <> - sp<hal::V1_1::IDevice> getDevice() const { + sp<V1_1::IDevice> getDevice() const { return mDeviceV1_1; } template <> - sp<hal::V1_2::IDevice> getDevice() const { + sp<V1_2::IDevice> getDevice() const { return mDeviceV1_2; } template <> - sp<hal::V1_3::IDevice> getDevice() const { + sp<V1_3::IDevice> getDevice() const { return mDeviceV1_3; } @@ -511,10 +512,10 @@ class VersionedIDevice { * Idiomatic usage: if mDeviceV1_1 is non-null, do V1_1 dispatch; otherwise, * do V1_0 dispatch. */ - sp<hal::V1_0::IDevice> mDeviceV1_0; - sp<hal::V1_1::IDevice> mDeviceV1_1; - sp<hal::V1_2::IDevice> mDeviceV1_2; - sp<hal::V1_3::IDevice> mDeviceV1_3; + sp<V1_0::IDevice> mDeviceV1_0; + sp<V1_1::IDevice> mDeviceV1_1; + sp<V1_2::IDevice> mDeviceV1_2; + sp<V1_3::IDevice> mDeviceV1_3; /** * HIDL callback to be invoked if the service for mDeviceV1_0 crashes. @@ -548,16 +549,16 @@ class VersionedIDevice { // If a callback is provided, this method protects it against driver death // and waits for it (callback->wait()). template <typename T_Return, typename T_IDevice, typename T_Callback = std::nullptr_t> - hal::Return<T_Return> recoverable( + hardware::Return<T_Return> recoverable( const char* context, - const std::function<hal::Return<T_Return>(const sp<T_IDevice>&)>& fn, + const std::function<hardware::Return<T_Return>(const sp<T_IDevice>&)>& fn, const T_Callback& callback = nullptr) const EXCLUDES(mMutex); // The name of the service that implements the driver. const std::string kServiceName; // Factory function object to generate an IDevice object. - const hal::DeviceFactory kMakeDevice; + const HalDeviceFactory kMakeDevice; // Guards access to mCore. mutable std::shared_mutex mMutex; @@ -591,7 +592,7 @@ class VersionedIPreparedModel { * the case when the service containing the IDevice * object crashes. */ - VersionedIPreparedModel(sp<hal::V1_0::IPreparedModel> preparedModel, + VersionedIPreparedModel(sp<V1_0::IPreparedModel> preparedModel, sp<IPreparedModelDeathHandler> deathHandler); /** @@ -676,10 +677,9 @@ class VersionedIPreparedModel { * UINT64_MAX. A driver may choose to report any time as UINT64_MAX, * indicating that measurement is not available. */ - std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> execute( - const hal::Request& request, hal::MeasureTiming measure, - const std::optional<Deadline>& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration, bool preferSynchronous) const; + std::tuple<int, std::vector<OutputShape>, Timing> execute( + const Request& request, MeasureTiming measure, const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, bool preferSynchronous) const; /** * Creates a burst controller on a prepared model. @@ -763,30 +763,28 @@ class VersionedIPreparedModel { * sync execution. Either IFencedExecutionCallback will be * returned or optional timing information is returned */ - std::tuple<int, hal::hidl_handle, sp<hal::IFencedExecutionCallback>, hal::Timing> executeFenced( - const hal::Request& request, const hal::hidl_vec<hal::hidl_handle>& waitFor, - hal::MeasureTiming measure, const std::optional<Deadline>& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration, - const hal::OptionalTimeoutDuration& timeoutDurationAfterFence); + std::tuple<int, hardware::hidl_handle, sp<V1_3::IFencedExecutionCallback>, Timing> + executeFenced(const Request& request, const hardware::hidl_vec<hardware::hidl_handle>& waitFor, + MeasureTiming measure, const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + const OptionalTimeoutDuration& timeoutDurationAfterFence); private: friend class VersionedIDevice; - std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> executeAsynchronously( - const hal::Request& request, hal::MeasureTiming timing, - const std::optional<Deadline>& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration) const; - std::tuple<int, std::vector<hal::OutputShape>, hal::Timing> executeSynchronously( - const hal::Request& request, hal::MeasureTiming measure, - const std::optional<Deadline>& deadline, - const hal::OptionalTimeoutDuration& loopTimeoutDuration) const; + std::tuple<int, std::vector<OutputShape>, Timing> executeAsynchronously( + const Request& request, MeasureTiming timing, const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration) const; + std::tuple<int, std::vector<OutputShape>, Timing> executeSynchronously( + const Request& request, MeasureTiming measure, const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration) const; /** * Returns sp<V1_3::IPreparedModel> that is a downcast of the sp<V1_0::IPreparedModel> * passed to the constructor. This will be nullptr if that IPreparedModel is * not actually of the specified downcast type. */ - sp<hal::V1_3::IPreparedModel> getV1_3() const { return mPreparedModelV1_3; } + sp<V1_3::IPreparedModel> getV1_3() const { return mPreparedModelV1_3; } /** * All versions of IPreparedModel are necessary because the preparedModel could be v1.0, @@ -810,9 +808,9 @@ class VersionedIPreparedModel { * otherwise, if mPreparedModelV1_2 is non-null, do V1_2 dispatch; * otherwise, do V1_0 dispatch. */ - sp<hal::V1_0::IPreparedModel> mPreparedModelV1_0; - sp<hal::V1_2::IPreparedModel> mPreparedModelV1_2; - sp<hal::V1_3::IPreparedModel> mPreparedModelV1_3; + sp<V1_0::IPreparedModel> mPreparedModelV1_0; + sp<V1_2::IPreparedModel> mPreparedModelV1_2; + sp<V1_3::IPreparedModel> mPreparedModelV1_3; /** * HIDL callback to be invoked if the service for mPreparedModelV1_0 crashes. diff --git a/nn/runtime/test/Android.bp b/nn/runtime/test/Android.bp index 4ea388a1f..ac53b9a10 100644 --- a/nn/runtime/test/Android.bp +++ b/nn/runtime/test/Android.bp @@ -134,8 +134,6 @@ cc_defaults { "fibonacci_extension/FibonacciExtensionTest.cpp", "TestMain.cpp", - - "Bridge.cpp", ], static_libs: [ "android.hardware.neuralnetworks@1.0-adapter-helper", diff --git a/nn/runtime/test/Bridge.cpp b/nn/runtime/test/Bridge.cpp deleted file mode 100644 index 574025620..000000000 --- a/nn/runtime/test/Bridge.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -// There are name clashes between NeuralNetworksWrapper.h and -// HalInterfaces.h. Many tests include the former; many internal -// header files (nn/runtime/*.h) include the latter. This file -// contains a few utilities for tests to call that trampoline to the -// internal headers. - -#include "GraphDump.h" -#include "ModelBuilder.h" - -namespace android { -namespace nn { -namespace bridge_tests { - -void graphDump(const char* name, const ModelBuilder* model, std::ostream* outStream) { - ::android::nn::graphDump(name, model->makeHidlModel(), outStream); -} - -} // namespace bridge_tests -} // namespace nn -} // namespace android diff --git a/nn/runtime/test/Bridge.h b/nn/runtime/test/Bridge.h deleted file mode 100644 index f067df0f3..000000000 --- a/nn/runtime/test/Bridge.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -// There are name clashes between NeuralNetworksWrapper.h and -// HalInterfaces.h. Many tests include the former; many internal -// header files (nn/runtime/*.h) include the latter. This file -// contains a few utilities for tests to call that trampoline to the -// internal headers. - -#ifndef ANDROID_FRAMEWORKS_ML_NN_RUNTIME_TEST_BRIDGE_H -#define ANDROID_FRAMEWORKS_ML_NN_RUNTIME_TEST_BRIDGE_H - -#include <iostream> - -namespace android { -namespace nn { - -class ModelBuilder; - -namespace bridge_tests { - -void graphDump(const char* name, const ModelBuilder* model, std::ostream* outStream = &std::cout); - -} // namespace bridge_tests - -} // namespace nn -} // namespace android - -#endif // ANDROID_FRAMEWORKS_ML_NN_RUNTIME_TEST_BRIDGE_H diff --git a/nn/runtime/test/TestCompilationCaching.cpp b/nn/runtime/test/TestCompilationCaching.cpp index 2311685d5..1a1cdc6c2 100644 --- a/nn/runtime/test/TestCompilationCaching.cpp +++ b/nn/runtime/test/TestCompilationCaching.cpp @@ -31,16 +31,17 @@ #include "TestNeuralNetworksWrapper.h" using namespace android::nn; -using namespace hal; -using Result = test_wrapper::Result; +namespace hardware = android::hardware; +using WrapperResult = test_wrapper::Result; using Type = test_wrapper::Type; -const Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; +const V1_2::Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; template <typename T> using MQDescriptorSync = ::android::hardware::MQDescriptorSync<T>; +using android::sp; namespace android::hardware::neuralnetworks::V1_0 { -::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) { +::std::ostream& operator<<(::std::ostream& os, V1_3::ErrorStatus errorStatus) { return os << toString(errorStatus); } @@ -66,10 +67,10 @@ std::ostream& operator<<(std::ostream& os, HasCalledPrepareModel hasCalledPrepar } // Whether the driver is expected to be registered because it can pass initialization. -bool canDeviceBeRegistered(ErrorStatus error, uint32_t numModelCache, uint32_t numDataCache) { +bool canDeviceBeRegistered(V1_3::ErrorStatus error, uint32_t numModelCache, uint32_t numDataCache) { constexpr uint32_t maxNumCacheFiles = - static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES); - return error == ErrorStatus::NONE && numModelCache <= maxNumCacheFiles && + static_cast<uint32_t>(V1_2::Constant::MAX_NUMBER_OF_CACHE_FILES); + return error == V1_3::ErrorStatus::NONE && numModelCache <= maxNumCacheFiles && numDataCache <= maxNumCacheFiles; } @@ -94,55 +95,59 @@ class CachingDriver : public sample_driver::SampleDriver { private: static constexpr size_t kCacheSize = 256; - class CachingPreparedModel : public IPreparedModel { + class CachingPreparedModel : public V1_3::IPreparedModel { public: CachingPreparedModel() = default; - Return<V1_0::ErrorStatus> execute(const V1_0::Request&, - const sp<V1_0::IExecutionCallback>&) override { + hardware::Return<V1_0::ErrorStatus> execute(const V1_0::Request&, + const sp<V1_0::IExecutionCallback>&) override { return V1_0::ErrorStatus::DEVICE_UNAVAILABLE; } - Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request&, MeasureTiming, - const sp<V1_2::IExecutionCallback>&) override { + hardware::Return<V1_0::ErrorStatus> execute_1_2( + const V1_0::Request&, V1_2::MeasureTiming, + const sp<V1_2::IExecutionCallback>&) override { return V1_0::ErrorStatus::DEVICE_UNAVAILABLE; } - Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request&, MeasureTiming, - const OptionalTimePoint&, - const OptionalTimeoutDuration&, - const sp<V1_3::IExecutionCallback>&) override { + hardware::Return<V1_3::ErrorStatus> execute_1_3( + const V1_3::Request&, V1_2::MeasureTiming, const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + const sp<V1_3::IExecutionCallback>&) override { return V1_3::ErrorStatus::DEVICE_UNAVAILABLE; } - Return<void> executeSynchronously(const V1_0::Request&, MeasureTiming, - executeSynchronously_cb cb) override { + hardware::Return<void> executeSynchronously(const V1_0::Request&, V1_2::MeasureTiming, + executeSynchronously_cb cb) override { cb(V1_0::ErrorStatus::DEVICE_UNAVAILABLE, {}, kBadTiming); - return Void(); + return hardware::Void(); } - Return<void> executeSynchronously_1_3(const V1_3::Request&, MeasureTiming, - const OptionalTimePoint&, - const OptionalTimeoutDuration&, - executeSynchronously_1_3_cb cb) override { + hardware::Return<void> executeSynchronously_1_3(const V1_3::Request&, V1_2::MeasureTiming, + const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + executeSynchronously_1_3_cb cb) override { cb(V1_3::ErrorStatus::DEVICE_UNAVAILABLE, {}, kBadTiming); - return Void(); + return hardware::Void(); } - Return<void> configureExecutionBurst(const sp<V1_2::IBurstCallback>&, - const MQDescriptorSync<V1_2::FmqRequestDatum>&, - const MQDescriptorSync<V1_2::FmqResultDatum>&, - configureExecutionBurst_cb cb) override { + hardware::Return<void> configureExecutionBurst( + const sp<V1_2::IBurstCallback>&, const MQDescriptorSync<V1_2::FmqRequestDatum>&, + const MQDescriptorSync<V1_2::FmqResultDatum>&, + configureExecutionBurst_cb cb) override { cb(V1_0::ErrorStatus::DEVICE_UNAVAILABLE, nullptr); - return Void(); + return hardware::Void(); } - Return<void> executeFenced(const hal::Request&, const hidl_vec<hidl_handle>&, MeasureTiming, - const OptionalTimePoint&, const OptionalTimeoutDuration&, - const OptionalTimeoutDuration&, executeFenced_cb cb) { - cb(ErrorStatus::DEVICE_UNAVAILABLE, hidl_handle(nullptr), nullptr); - return Void(); + hardware::Return<void> executeFenced(const V1_3::Request&, + const hardware::hidl_vec<hardware::hidl_handle>&, + V1_2::MeasureTiming, const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + const V1_3::OptionalTimeoutDuration&, + executeFenced_cb cb) { + cb(V1_3::ErrorStatus::DEVICE_UNAVAILABLE, hardware::hidl_handle(nullptr), nullptr); + return hardware::Void(); } }; public: - CachingDriver(std::string_view name, ErrorStatus errorStatusGetNumCacheFiles, + CachingDriver(std::string_view name, V1_3::ErrorStatus errorStatusGetNumCacheFiles, uint32_t numModelCache, uint32_t numDataCache, - ErrorStatus errorStatusPrepareFromCache) + V1_3::ErrorStatus errorStatusPrepareFromCache) : SampleDriver(name.data()), mErrorStatusGetNumCacheFiles(errorStatusGetNumCacheFiles), mNumModelCache(numModelCache), @@ -156,39 +161,40 @@ class CachingDriver : public sample_driver::SampleDriver { ~CachingDriver() override {} // Reports faster than cpu. - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { android::nn::initVLogMask(); - const PerformanceInfo kPerf = {.execTime = 0.1, .powerUsage = 0.1}; - Capabilities capabilities = { + const V1_0::PerformanceInfo kPerf = {.execTime = 0.1, .powerUsage = 0.1}; + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = kPerf, .relaxedFloat32toFloat16PerformanceTensor = kPerf, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>(kPerf), .ifPerformance = kPerf, .whilePerformance = kPerf}; cb(V1_3::ErrorStatus::NONE, capabilities); - return Void(); + return hardware::Void(); } // Reports supporting all operations. - Return<void> getSupportedOperations_1_3(const Model& model, - getSupportedOperations_1_3_cb cb) override { + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model& model, + getSupportedOperations_1_3_cb cb) override { std::vector<bool> supported(model.main.operations.size(), true); cb(V1_3::ErrorStatus::NONE, supported); - return Void(); + return hardware::Void(); } // Reports according to mGetNumCacheFiles. - Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) override { + hardware::Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) override { cb(convertToV1_0(mErrorStatusGetNumCacheFiles), mNumModelCache, mNumDataCache); - return Void(); + return hardware::Void(); } // Generates CachingPreparedModel. // Writes the cache entry per mCacheXData and sets mHasCalledPrepareModel. - Return<V1_3::ErrorStatus> prepareModel_1_3( - const Model&, ExecutionPreference, Priority, const OptionalTimePoint&, - const hidl_vec<hidl_handle>& modelCacheHandle, - const hidl_vec<hidl_handle>& dataCacheHandle, const CacheToken&, + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const V1_3::Model&, V1_1::ExecutionPreference, V1_3::Priority, + const V1_3::OptionalTimePoint&, + const hardware::hidl_vec<hardware::hidl_handle>& modelCacheHandle, + const hardware::hidl_vec<hardware::hidl_handle>& dataCacheHandle, const HalCacheToken&, const sp<V1_3::IPreparedModelCallback>& cb) override { checkNumberOfCacheHandles(modelCacheHandle.size(), dataCacheHandle.size()); if (modelCacheHandle.size() != 0 || dataCacheHandle.size() != 0) { @@ -204,9 +210,10 @@ class CachingDriver : public sample_driver::SampleDriver { // Checks if the cache entry is correct, notifies error status according to // mErrorStatusPrepareFromCache, sets mHasCalledPrepareModelFromCache. - Return<V1_3::ErrorStatus> prepareModelFromCache_1_3( - const OptionalTimePoint&, const hidl_vec<hidl_handle>& modelCacheHandle, - const hidl_vec<hidl_handle>& dataCacheHandle, const CacheToken&, + hardware::Return<V1_3::ErrorStatus> prepareModelFromCache_1_3( + const V1_3::OptionalTimePoint&, + const hardware::hidl_vec<hardware::hidl_handle>& modelCacheHandle, + const hardware::hidl_vec<hardware::hidl_handle>& dataCacheHandle, const HalCacheToken&, const sp<V1_3::IPreparedModelCallback>& callback) override { readFromCache(modelCacheHandle, mModelCacheData); readFromCache(dataCacheHandle, mDataCacheData); @@ -236,7 +243,8 @@ class CachingDriver : public sample_driver::SampleDriver { } } - void writeToCache(const hidl_vec<hidl_handle>& handles, const std::vector<uint8_t>& cache) { + void writeToCache(const hardware::hidl_vec<hardware::hidl_handle>& handles, + const std::vector<uint8_t>& cache) { for (uint32_t i = 0; i < handles.size(); ++i) { ASSERT_EQ(handles[i]->numFds, 1); EXPECT_EQ(write(handles[i]->data[0], cache.data(), kCacheSize), @@ -244,7 +252,8 @@ class CachingDriver : public sample_driver::SampleDriver { } } - void readFromCache(const hidl_vec<hidl_handle>& handles, const std::vector<uint8_t>& expected) { + void readFromCache(const hardware::hidl_vec<hardware::hidl_handle>& handles, + const std::vector<uint8_t>& expected) { for (uint32_t i = 0; i < handles.size(); ++i) { ASSERT_EQ(handles[i]->numFds, 1); std::vector<uint8_t> actual(kCacheSize); @@ -257,10 +266,10 @@ class CachingDriver : public sample_driver::SampleDriver { std::vector<uint8_t> mModelCacheData; std::vector<uint8_t> mDataCacheData; - const ErrorStatus mErrorStatusGetNumCacheFiles; + const V1_3::ErrorStatus mErrorStatusGetNumCacheFiles; const uint32_t mNumModelCache; const uint32_t mNumDataCache; - const ErrorStatus mErrorStatusPrepareFromCache; + const V1_3::ErrorStatus mErrorStatusPrepareFromCache; bool mHasCalledPrepareModelFromCache = false; HasCalledPrepareModel mHasCalledPrepareModel = HasCalledPrepareModel::NO; @@ -279,7 +288,7 @@ void CreateBroadcastAddModel(test_wrapper::Model* model) { model->addOperation(ANEURALNETWORKS_ADD, {a, b, d}, {c}); model->identifyInputsAndOutputs({a, b}, {c}); ASSERT_TRUE(model->isValid()); - ASSERT_EQ(model->finish(), Result::NO_ERROR); + ASSERT_EQ(model->finish(), WrapperResult::NO_ERROR); } void getDeviceWithName(std::string_view deviceName, const ANeuralNetworksDevice** outputDevice) { @@ -307,17 +316,17 @@ void getDeviceWithName(std::string_view deviceName, const ANeuralNetworksDevice* // - ErrorStatus returning from getNumberOfCacheFilesNeeded // - Number of model cache files returning from getNumberOfCacheFilesNeeded // - Number of data cache files returning from getNumberOfCacheFilesNeeded -using DeviceRegistrationTestParam = std::tuple<ErrorStatus, uint32_t, uint32_t>; +using DeviceRegistrationTestParam = std::tuple<V1_3::ErrorStatus, uint32_t, uint32_t>; class DeviceRegistrationTest : public ::testing::TestWithParam<DeviceRegistrationTestParam> { protected: static constexpr std::string_view kDeviceName = "deviceTestCompilationCaching"; - const ErrorStatus kErrorStatusGetNumCacheFiles = std::get<0>(GetParam()); + const V1_3::ErrorStatus kErrorStatusGetNumCacheFiles = std::get<0>(GetParam()); const uint32_t kNumModelCache = std::get<1>(GetParam()); const uint32_t kNumDataCache = std::get<2>(GetParam()); const sp<CachingDriver> kDriver = new CachingDriver(kDeviceName, kErrorStatusGetNumCacheFiles, kNumModelCache, - kNumDataCache, ErrorStatus::NONE); + kNumDataCache, V1_3::ErrorStatus::NONE); }; TEST_P(DeviceRegistrationTest, CachingFailure) { @@ -344,7 +353,7 @@ TEST_P(DeviceRegistrationTest, CachingFailure) { // - Number of model cache files returning from getNumberOfCacheFilesNeeded // - Number of data cache files returning from getNumberOfCacheFilesNeeded // - ErrorStatus returning from prepareModelFromCache_1_3 -using CompilationCachingTestParam = std::tuple<uint32_t, uint32_t, ErrorStatus>; +using CompilationCachingTestParam = std::tuple<uint32_t, uint32_t, V1_3::ErrorStatus>; class CompilationCachingTest : public ::testing::TestWithParam<CompilationCachingTestParam> { protected: @@ -390,27 +399,29 @@ class CompilationCachingTest : public ::testing::TestWithParam<CompilationCachin } void createCache() { - sp<CachingDriver> driver = new CachingDriver(kDeviceName, ErrorStatus::NONE, kNumModelCache, - kNumDataCache, ErrorStatus::NONE); + sp<CachingDriver> driver = + new CachingDriver(kDeviceName, V1_3::ErrorStatus::NONE, kNumModelCache, + kNumDataCache, V1_3::ErrorStatus::NONE); compileModel(driver, /*withToken=*/true); } static constexpr std::string_view kDeviceName = "deviceTestCompilationCaching"; const uint32_t kNumModelCache = std::get<0>(GetParam()); const uint32_t kNumDataCache = std::get<1>(GetParam()); - const ErrorStatus kErrorStatusPrepareFromCache = std::get<2>(GetParam()); + const V1_3::ErrorStatus kErrorStatusPrepareFromCache = std::get<2>(GetParam()); const bool kIsCachingSupported = isCachingSupported(kNumModelCache, kNumDataCache); test_wrapper::Model mModel; std::string mCacheDir; - const CacheToken kToken{}; + const HalCacheToken kToken{}; }; TEST_P(CompilationCachingTest, TokenProvidedAndCacheNotExist) { if (DeviceManager::get()->getUseCpuOnly()) { return; } - sp<CachingDriver> driver = new CachingDriver(kDeviceName, ErrorStatus::NONE, kNumModelCache, - kNumDataCache, kErrorStatusPrepareFromCache); + sp<CachingDriver> driver = + new CachingDriver(kDeviceName, V1_3::ErrorStatus::NONE, kNumModelCache, kNumDataCache, + kErrorStatusPrepareFromCache); compileModel(driver, /*withToken=*/true); // When cache file does not exist, the runtime should never call prepareModelFromCache_1_3. @@ -427,8 +438,9 @@ TEST_P(CompilationCachingTest, TokenProvidedAndCacheExist) { return; } createCache(); - sp<CachingDriver> driver = new CachingDriver(kDeviceName, ErrorStatus::NONE, kNumModelCache, - kNumDataCache, kErrorStatusPrepareFromCache); + sp<CachingDriver> driver = + new CachingDriver(kDeviceName, V1_3::ErrorStatus::NONE, kNumModelCache, kNumDataCache, + kErrorStatusPrepareFromCache); compileModel(driver, /*withToken=*/true); // When cache files exist, the runtime should call prepareModelFromCache_1_3 iff caching @@ -437,7 +449,7 @@ TEST_P(CompilationCachingTest, TokenProvidedAndCacheExist) { HasCalledPrepareModel expectHasCalledPrepareModel; if (kIsCachingSupported) { - if (kErrorStatusPrepareFromCache == ErrorStatus::NONE) { + if (kErrorStatusPrepareFromCache == V1_3::ErrorStatus::NONE) { // The runtime should not call prepareModel_1_3 iff caching supported and // prepareModelFromCache_1_3 succeeds. expectHasCalledPrepareModel = HasCalledPrepareModel::NO; @@ -457,8 +469,9 @@ TEST_P(CompilationCachingTest, TokenNotProvided) { if (DeviceManager::get()->getUseCpuOnly()) { return; } - sp<CachingDriver> driver = new CachingDriver(kDeviceName, ErrorStatus::NONE, kNumModelCache, - kNumDataCache, kErrorStatusPrepareFromCache); + sp<CachingDriver> driver = + new CachingDriver(kDeviceName, V1_3::ErrorStatus::NONE, kNumModelCache, kNumDataCache, + kErrorStatusPrepareFromCache); compileModel(driver, /*withToken=*/false); // When no NDK token is provided by the client, the runtime should never call @@ -468,15 +481,15 @@ TEST_P(CompilationCachingTest, TokenNotProvided) { } static const auto kErrorStatusGetNumCacheFilesChoices = - testing::Values(ErrorStatus::NONE, ErrorStatus::DEVICE_UNAVAILABLE); + testing::Values(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::DEVICE_UNAVAILABLE); static const auto kNumCacheChoices = - testing::Values(0ul, 1ul, static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES), - static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES) + 1); + testing::Values(0ul, 1ul, static_cast<uint32_t>(V1_2::Constant::MAX_NUMBER_OF_CACHE_FILES), + static_cast<uint32_t>(V1_2::Constant::MAX_NUMBER_OF_CACHE_FILES) + 1); static const auto kNumValidCacheChoices = - testing::Values(0ul, 1ul, static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES)); + testing::Values(0ul, 1ul, static_cast<uint32_t>(V1_2::Constant::MAX_NUMBER_OF_CACHE_FILES)); static const auto kErrorStatusPrepareFromCacheChoices = - testing::Values(ErrorStatus::NONE, ErrorStatus::GENERAL_FAILURE, - ErrorStatus::DEVICE_UNAVAILABLE, ErrorStatus::INVALID_ARGUMENT); + testing::Values(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, + V1_3::ErrorStatus::DEVICE_UNAVAILABLE, V1_3::ErrorStatus::INVALID_ARGUMENT); INSTANTIATE_TEST_SUITE_P(TestCompilationCaching, DeviceRegistrationTest, testing::Combine(kErrorStatusGetNumCacheFilesChoices, kNumCacheChoices, diff --git a/nn/runtime/test/TestCompliance.cpp b/nn/runtime/test/TestCompliance.cpp index d756c2414..299eebcf7 100644 --- a/nn/runtime/test/TestCompliance.cpp +++ b/nn/runtime/test/TestCompliance.cpp @@ -27,7 +27,6 @@ namespace android::nn::compliance_test { -using namespace hal; using namespace test_helper; using HidlModel = V1_3::Model; using WrapperModel = test_wrapper::Model; @@ -42,7 +41,7 @@ static HidlModel createHidlModel(const WrapperModel& wrapperModel) { auto modelBuilder = reinterpret_cast<const ModelBuilder*>(wrapperModel.getHandle()); EXPECT_TRUE(modelBuilder->isFinished()); EXPECT_TRUE(modelBuilder->isValid()); - return modelBuilder->makeHidlModel(); + return convertToV1_3(modelBuilder->makeModel()); } static void testAvailableSinceV1_3(const WrapperModel& wrapperModel) { @@ -73,12 +72,12 @@ static void testAvailableSinceV1_0(const WrapperModel& wrapperModel) { ASSERT_TRUE(compliantWithV1_0(hidlModel)); } -static void testAvailableSinceV1_2(const Request& request) { +static void testAvailableSinceV1_2(const V1_3::Request& request) { ASSERT_FALSE(compliantWithV1_0(request)); ASSERT_TRUE(compliantWithV1_2(request)); } -static void testAvailableSinceV1_3(const Request& request) { +static void testAvailableSinceV1_3(const V1_3::Request& request) { ASSERT_FALSE(compliantWithV1_0(request)); ASSERT_FALSE(compliantWithV1_2(request)); } @@ -172,20 +171,20 @@ TEST_F(ComplianceTest, HardwareBufferModel) { TEST_F(ComplianceTest, HardwareBufferRequest) { const auto [n, ahwb] = MemoryRuntimeAHWB::create(1024); ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - Request::MemoryPool sharedMemoryPool, ahwbMemoryPool = ahwb->getMemoryPool(); + V1_3::Request::MemoryPool sharedMemoryPool, ahwbMemoryPool = ahwb->getMemoryPool(); sharedMemoryPool.hidlMemory(allocateSharedMemory(1024)); ASSERT_TRUE(sharedMemoryPool.hidlMemory().valid()); ASSERT_TRUE(ahwbMemoryPool.hidlMemory().valid()); // AHardwareBuffer as input. - testAvailableSinceV1_2(Request{ + testAvailableSinceV1_2(V1_3::Request{ .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}}, .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}}, .pools = {ahwbMemoryPool, sharedMemoryPool}, }); // AHardwareBuffer as output. - testAvailableSinceV1_2(Request{ + testAvailableSinceV1_2(V1_3::Request{ .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}}, .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}}, .pools = {sharedMemoryPool, ahwbMemoryPool}, @@ -194,20 +193,20 @@ TEST_F(ComplianceTest, HardwareBufferRequest) { #endif TEST_F(ComplianceTest, DeviceMemory) { - Request::MemoryPool sharedMemoryPool, deviceMemoryPool; + V1_3::Request::MemoryPool sharedMemoryPool, deviceMemoryPool; sharedMemoryPool.hidlMemory(allocateSharedMemory(1024)); ASSERT_TRUE(sharedMemoryPool.hidlMemory().valid()); deviceMemoryPool.token(1); // Device memory as input. - testAvailableSinceV1_3(Request{ + testAvailableSinceV1_3(V1_3::Request{ .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}}, .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}}, .pools = {deviceMemoryPool, sharedMemoryPool}, }); // Device memory as output. - testAvailableSinceV1_3(Request{ + testAvailableSinceV1_3(V1_3::Request{ .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}}, .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}}, .pools = {sharedMemoryPool, deviceMemoryPool}, diff --git a/nn/runtime/test/TestExecution.cpp b/nn/runtime/test/TestExecution.cpp index 3441f9fc4..5f012c3eb 100644 --- a/nn/runtime/test/TestExecution.cpp +++ b/nn/runtime/test/TestExecution.cpp @@ -38,49 +38,54 @@ namespace android { -using namespace nn::hal; +namespace V1_0 = ::android::hardware::neuralnetworks::V1_0; +namespace V1_1 = ::android::hardware::neuralnetworks::V1_1; +namespace V1_2 = ::android::hardware::neuralnetworks::V1_2; +namespace V1_3 = ::android::hardware::neuralnetworks::V1_3; using CompilationBuilder = nn::CompilationBuilder; using Device = nn::Device; using DeviceManager = nn::DeviceManager; using HidlModel = V1_3::Model; using PreparedModelCallback = nn::PreparedModelCallback; -using Result = nn::test_wrapper::Result; using SampleDriver = nn::sample_driver::SampleDriver; using WrapperCompilation = nn::test_wrapper::Compilation; using WrapperEvent = nn::test_wrapper::Event; using WrapperExecution = nn::test_wrapper::Execution; using WrapperModel = nn::test_wrapper::Model; using WrapperOperandType = nn::test_wrapper::OperandType; +using WrapperResult = nn::test_wrapper::Result; using WrapperType = nn::test_wrapper::Type; using nn::convertToV1_0; +using nn::convertToV1_3; +using nn::ErrorStatus; template <typename T> using MQDescriptorSync = hardware::MQDescriptorSync<T>; namespace { -const Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; +const V1_2::Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; // Wraps the latest version of IPreparedModel to allow dummying up the execution status, // and control when the execution finishes. -class TestPreparedModelLatest : public IPreparedModel { +class TestPreparedModelLatest : public V1_3::IPreparedModel { public: // If errorStatus is NONE, then execute behaves normally (and sends back // the actual execution status). Otherwise, don't bother to execute, and // just send back errorStatus (as the execution status, not the launch // status). - TestPreparedModelLatest(sp<V1_0::IPreparedModel> preparedModel, ErrorStatus errorStatus) + TestPreparedModelLatest(sp<V1_0::IPreparedModel> preparedModel, V1_3::ErrorStatus errorStatus) : mPreparedModelV1_0(preparedModel), mPreparedModelV1_2(V1_2::IPreparedModel::castFrom(preparedModel).withDefault(nullptr)), mPreparedModelV1_3(V1_3::IPreparedModel::castFrom(preparedModel).withDefault(nullptr)), mErrorStatus(errorStatus) {} - Return<V1_0::ErrorStatus> execute(const V1_0::Request& request, - const sp<V1_0::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) override { CHECK(mPreparedModelV1_0 != nullptr) << "V1_0 prepared model is nullptr."; std::thread([this, request, callback] { dummyExecution(); - if (mErrorStatus == ErrorStatus::NONE) { + if (mErrorStatus == V1_3::ErrorStatus::NONE) { // Note that we lose the actual launch status. (void)mPreparedModelV1_0->execute(request, callback); } else { @@ -90,16 +95,17 @@ class TestPreparedModelLatest : public IPreparedModel { return V1_0::ErrorStatus::NONE; } - Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request& request, MeasureTiming measure, - const sp<V1_2::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute_1_2( + const V1_0::Request& request, V1_2::MeasureTiming measure, + const sp<V1_2::IExecutionCallback>& callback) override { CHECK(mPreparedModelV1_2 != nullptr) << "V1_2 prepared model is nullptr."; std::thread([this, request, measure, callback] { dummyExecution(); - if (mErrorStatus == ErrorStatus::NONE) { + if (mErrorStatus == V1_3::ErrorStatus::NONE) { // Note that we lose the actual launch status. (void)mPreparedModelV1_2->execute_1_2(request, measure, callback); - } else if (mErrorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { - OutputShape shape = {.dimensions = {1}, .isSufficient = false}; + } else if (mErrorStatus == V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + V1_2::OutputShape shape = {.dimensions = {1}, .isSufficient = false}; callback->notify_1_2(convertToV1_0(mErrorStatus), {shape}, kBadTiming); } else { callback->notify_1_2(convertToV1_0(mErrorStatus), {}, kBadTiming); @@ -108,19 +114,20 @@ class TestPreparedModelLatest : public IPreparedModel { return V1_0::ErrorStatus::NONE; } - Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request& request, MeasureTiming measure, - const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const sp<V1_3::IExecutionCallback>& callback) override { + hardware::Return<V1_3::ErrorStatus> execute_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const sp<V1_3::IExecutionCallback>& callback) override { CHECK(mPreparedModelV1_3 != nullptr) << "V1_3 prepared model is nullptr."; std::thread([this, request, measure, deadline, loopTimeoutDuration, callback] { dummyExecution(); - if (mErrorStatus == ErrorStatus::NONE) { + if (mErrorStatus == V1_3::ErrorStatus::NONE) { // Note that we lose the actual launch status. (void)mPreparedModelV1_3->execute_1_3(request, measure, deadline, loopTimeoutDuration, callback); - } else if (mErrorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { - OutputShape shape = {.dimensions = {1}, .isSufficient = false}; + } else if (mErrorStatus == V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + V1_2::OutputShape shape = {.dimensions = {1}, .isSufficient = false}; callback->notify_1_3(mErrorStatus, {shape}, kBadTiming); } else { callback->notify_1_3(mErrorStatus, {}, kBadTiming); @@ -129,53 +136,55 @@ class TestPreparedModelLatest : public IPreparedModel { return V1_3::ErrorStatus::NONE; } - Return<void> executeSynchronously(const V1_0::Request& request, MeasureTiming measure, - executeSynchronously_cb cb) override { + hardware::Return<void> executeSynchronously(const V1_0::Request& request, + V1_2::MeasureTiming measure, + executeSynchronously_cb cb) override { CHECK(mPreparedModelV1_2 != nullptr) << "V1_2 prepared model is nullptr."; dummyExecution(); - if (mErrorStatus == ErrorStatus::NONE) { + if (mErrorStatus == V1_3::ErrorStatus::NONE) { return mPreparedModelV1_2->executeSynchronously(request, measure, cb); - } else if (mErrorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { - OutputShape shape = {.dimensions = {1}, .isSufficient = false}; + } else if (mErrorStatus == V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + V1_2::OutputShape shape = {.dimensions = {1}, .isSufficient = false}; cb(convertToV1_0(mErrorStatus), {shape}, kBadTiming); - return Void(); + return hardware::Void(); } else { cb(convertToV1_0(mErrorStatus), {}, kBadTiming); - return Void(); + return hardware::Void(); } } - Return<void> executeSynchronously_1_3(const V1_3::Request& request, MeasureTiming measure, - const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - executeSynchronously_1_3_cb cb) override { + hardware::Return<void> executeSynchronously_1_3( + const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + executeSynchronously_1_3_cb cb) override { CHECK(mPreparedModelV1_3 != nullptr) << "V1_3 prepared model is nullptr."; dummyExecution(); - if (mErrorStatus == ErrorStatus::NONE) { + if (mErrorStatus == V1_3::ErrorStatus::NONE) { return mPreparedModelV1_3->executeSynchronously_1_3(request, measure, deadline, loopTimeoutDuration, cb); - } else if (mErrorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { - OutputShape shape = {.dimensions = {1}, .isSufficient = false}; + } else if (mErrorStatus == V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + V1_2::OutputShape shape = {.dimensions = {1}, .isSufficient = false}; cb(mErrorStatus, {shape}, kBadTiming); - return Void(); + return hardware::Void(); } else { cb(mErrorStatus, {}, kBadTiming); - return Void(); + return hardware::Void(); } } - Return<void> configureExecutionBurst( + hardware::Return<void> configureExecutionBurst( const sp<V1_2::IBurstCallback>& callback, const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, configureExecutionBurst_cb cb) override { CHECK(mPreparedModelV1_2 != nullptr) << "V1_2 prepared model is nullptr."; - if (mErrorStatus == ErrorStatus::NONE) { + if (mErrorStatus == V1_3::ErrorStatus::NONE) { return mPreparedModelV1_2->configureExecutionBurst(callback, requestChannel, resultChannel, cb); } else { cb(convertToV1_0(mErrorStatus), nullptr); - return Void(); + return hardware::Void(); } } @@ -184,25 +193,27 @@ class TestPreparedModelLatest : public IPreparedModel { // SampleDriver is written with that in mind. Therefore, this // implementation is synchronous also. If the SampleDriver is updated to // return real sync fence, this must be updated. - Return<void> executeFenced(const V1_3::Request& request, const hidl_vec<hidl_handle>& waitFor, - MeasureTiming measure, const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const OptionalTimeoutDuration& duration, - executeFenced_cb cb) override { + hardware::Return<void> executeFenced(const V1_3::Request& request, + const hardware::hidl_vec<hardware::hidl_handle>& waitFor, + V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const V1_3::OptionalTimeoutDuration& duration, + executeFenced_cb cb) override { CHECK(mPreparedModelV1_3 != nullptr) << "V1_3 prepared model is nullptr."; - CHECK(mErrorStatus != ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) + CHECK(mErrorStatus != V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) << "executeFenced does not support dynamic output shape"; dummyExecution(); - if (mErrorStatus == ErrorStatus::NONE) { + if (mErrorStatus == V1_3::ErrorStatus::NONE) { return mPreparedModelV1_3->executeFenced(request, waitFor, measure, deadline, loopTimeoutDuration, duration, cb); } else { // Due to the limitations of the SampleDriver, all failures look // like launch failures. If the SampleDriver is updated to return // real sync fences, this must be updated. - cb(mErrorStatus, hidl_handle(nullptr), nullptr); + cb(mErrorStatus, hardware::hidl_handle(nullptr), nullptr); } - return Void(); + return hardware::Void(); } // We can place the TestPreparedModelLatest system in a "pause" mode where @@ -225,7 +236,7 @@ class TestPreparedModelLatest : public IPreparedModel { const sp<V1_0::IPreparedModel> mPreparedModelV1_0; const sp<V1_2::IPreparedModel> mPreparedModelV1_2; const sp<V1_3::IPreparedModel> mPreparedModelV1_3; - ErrorStatus mErrorStatus; + V1_3::ErrorStatus mErrorStatus; static std::atomic<bool> mPauseExecutions; static std::atomic<unsigned int> mExecutionsInFlight; @@ -245,25 +256,27 @@ using TestPreparedModel13 = TestPreparedModelLatest; // Like TestPreparedModelLatest, but implementing 1.2 class TestPreparedModel12 : public V1_2::IPreparedModel { public: - TestPreparedModel12(sp<V1_0::IPreparedModel> preparedModel, ErrorStatus errorStatus) + TestPreparedModel12(sp<V1_0::IPreparedModel> preparedModel, V1_3::ErrorStatus errorStatus) : mLatestPreparedModel(new TestPreparedModelLatest(preparedModel, errorStatus)) {} - Return<V1_0::ErrorStatus> execute(const V1_0::Request& request, - const sp<V1_0::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) override { return mLatestPreparedModel->execute(request, callback); } - Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request& request, MeasureTiming measure, - const sp<V1_2::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute_1_2( + const V1_0::Request& request, V1_2::MeasureTiming measure, + const sp<V1_2::IExecutionCallback>& callback) override { return mLatestPreparedModel->execute_1_2(request, measure, callback); } - Return<void> executeSynchronously(const V1_0::Request& request, MeasureTiming measure, - executeSynchronously_cb cb) override { + hardware::Return<void> executeSynchronously(const V1_0::Request& request, + V1_2::MeasureTiming measure, + executeSynchronously_cb cb) override { return mLatestPreparedModel->executeSynchronously(request, measure, cb); } - Return<void> configureExecutionBurst( + hardware::Return<void> configureExecutionBurst( const sp<V1_2::IBurstCallback>& callback, const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, @@ -273,22 +286,22 @@ class TestPreparedModel12 : public V1_2::IPreparedModel { } private: - const sp<IPreparedModel> mLatestPreparedModel; + const sp<V1_3::IPreparedModel> mLatestPreparedModel; }; // Like TestPreparedModelLatest, but implementing 1.0 class TestPreparedModel10 : public V1_0::IPreparedModel { public: - TestPreparedModel10(sp<V1_0::IPreparedModel> preparedModel, ErrorStatus errorStatus) + TestPreparedModel10(sp<V1_0::IPreparedModel> preparedModel, V1_3::ErrorStatus errorStatus) : mLatestPreparedModel(new TestPreparedModelLatest(preparedModel, errorStatus)) {} - Return<V1_0::ErrorStatus> execute(const V1_0::Request& request, - const sp<V1_0::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) override { return mLatestPreparedModel->execute(request, callback); } private: - const sp<IPreparedModel> mLatestPreparedModel; + const sp<V1_3::IPreparedModel> mLatestPreparedModel; }; // Behaves like SampleDriver, except that it produces wrapped IPreparedModel. @@ -300,13 +313,13 @@ class TestDriver13 : public SampleDriver { // status). Otherwise, don't bother to execute, and just send // back errorStatus (as the execution status, not the launch // status). - TestDriver13(const std::string& name, ErrorStatus errorStatus) + TestDriver13(const std::string& name, V1_3::ErrorStatus errorStatus) : SampleDriver(name.c_str()), mErrorStatus(errorStatus) {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb _hidl_cb) override { android::nn::initVLogMask(); - const PerformanceInfo kPerf = {.execTime = 0.75f, .powerUsage = 0.75f}; - Capabilities capabilities = { + const V1_0::PerformanceInfo kPerf = {.execTime = 0.75f, .powerUsage = 0.75f}; + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = kPerf, .relaxedFloat32toFloat16PerformanceTensor = kPerf, .operandPerformance = @@ -314,41 +327,43 @@ class TestDriver13 : public SampleDriver { .ifPerformance = kPerf, .whilePerformance = kPerf}; _hidl_cb(V1_3::ErrorStatus::NONE, capabilities); - return Void(); + return hardware::Void(); } - Return<void> getSupportedOperations_1_3(const HidlModel& model, - getSupportedOperations_1_3_cb cb) override { + hardware::Return<void> getSupportedOperations_1_3(const HidlModel& model, + getSupportedOperations_1_3_cb cb) override { if (nn::validateModel(model)) { std::vector<bool> supported(model.main.operations.size(), true); cb(V1_3::ErrorStatus::NONE, supported); } else { cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}); } - return Void(); + return hardware::Void(); } - Return<V1_3::ErrorStatus> prepareModel_1_3( - const HidlModel& model, ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache, - const hidl_vec<hidl_handle>& dataCache, const CacheToken& token, + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const HidlModel& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const nn::HalCacheToken& token, const sp<V1_3::IPreparedModelCallback>& actualCallback) override { sp<PreparedModelCallback> localCallback = new PreparedModelCallback; - Return<V1_3::ErrorStatus> prepareModelReturn = SampleDriver::prepareModel_1_3( + hardware::Return<V1_3::ErrorStatus> prepareModelReturn = SampleDriver::prepareModel_1_3( model, preference, priority, deadline, modelCache, dataCache, token, localCallback); if (!prepareModelReturn.isOkUnchecked()) { return prepareModelReturn; } - if (prepareModelReturn != ErrorStatus::NONE) { + if (prepareModelReturn != V1_3::ErrorStatus::NONE) { actualCallback->notify_1_3( - localCallback->getStatus(), + convertToV1_3(localCallback->getStatus()), V1_3::IPreparedModel::castFrom(localCallback->getPreparedModel())); return prepareModelReturn; } localCallback->wait(); if (localCallback->getStatus() != ErrorStatus::NONE) { actualCallback->notify_1_3( - localCallback->getStatus(), + convertToV1_3(localCallback->getStatus()), V1_3::IPreparedModel::castFrom(localCallback->getPreparedModel())); } else { actualCallback->notify_1_3( @@ -358,13 +373,14 @@ class TestDriver13 : public SampleDriver { return prepareModelReturn; } - Return<V1_0::ErrorStatus> prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference preference, - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const nn::HalCacheToken& token, const sp<V1_2::IPreparedModelCallback>& actualCallback) override { sp<PreparedModelCallback> localCallback = new PreparedModelCallback; - Return<V1_0::ErrorStatus> prepareModelReturn = SampleDriver::prepareModel_1_2( + hardware::Return<V1_0::ErrorStatus> prepareModelReturn = SampleDriver::prepareModel_1_2( model, preference, modelCache, dataCache, token, localCallback); if (!prepareModelReturn.isOkUnchecked()) { return prepareModelReturn; @@ -388,11 +404,11 @@ class TestDriver13 : public SampleDriver { return prepareModelReturn; } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { sp<PreparedModelCallback> localCallback = new PreparedModelCallback; - Return<V1_0::ErrorStatus> prepareModelReturn = + hardware::Return<V1_0::ErrorStatus> prepareModelReturn = SampleDriver::prepareModel_1_1(model, preference, localCallback); if (!prepareModelReturn.isOkUnchecked()) { return prepareModelReturn; @@ -414,75 +430,79 @@ class TestDriver13 : public SampleDriver { return prepareModelReturn; } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { - return prepareModel_1_1(nn::convertToV1_1(model), ExecutionPreference::FAST_SINGLE_ANSWER, - actualCallback); + return prepareModel_1_1(nn::convertToV1_1(model), + V1_1::ExecutionPreference::FAST_SINGLE_ANSWER, actualCallback); } private: - ErrorStatus mErrorStatus; + V1_3::ErrorStatus mErrorStatus; }; // Like TestDriver, but implementing 1.2 class TestDriver12 : public V1_2::IDevice { public: - TestDriver12(const std::string& name, ErrorStatus errorStatus) + TestDriver12(const std::string& name, V1_3::ErrorStatus errorStatus) : mLatestDriver(new TestDriver13(name, errorStatus)) {} - Return<void> getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_2(_hidl_cb); } - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_1(_hidl_cb); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations_1_2(const V1_2::Model& model, - getSupportedOperations_1_2_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_2( + const V1_2::Model& model, getSupportedOperations_1_2_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_2(model, _hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_1(model, _hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference preference, - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const nn::HalCacheToken& token, const sp<V1_2::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_2(model, preference, modelCache, dataCache, token, actualCallback); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_1(model, preference, actualCallback); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } - Return<void> getVersionString(getVersionString_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<void> getVersionString(getVersionString_cb _hidl_cb) override { return mLatestDriver->getVersionString(_hidl_cb); } - Return<void> getType(getType_cb _hidl_cb) override { return mLatestDriver->getType(_hidl_cb); } - Return<void> getSupportedExtensions(getSupportedExtensions_cb _hidl_cb) { + hardware::Return<void> getType(getType_cb _hidl_cb) override { + return mLatestDriver->getType(_hidl_cb); + } + hardware::Return<void> getSupportedExtensions(getSupportedExtensions_cb _hidl_cb) { return mLatestDriver->getSupportedExtensions(_hidl_cb); } - Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb _hidl_cb) { + hardware::Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb _hidl_cb) { return mLatestDriver->getNumberOfCacheFilesNeeded(_hidl_cb); } - Return<V1_0::ErrorStatus> prepareModelFromCache( - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) { + hardware::Return<V1_0::ErrorStatus> prepareModelFromCache( + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const nn::HalCacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) { return mLatestDriver->prepareModelFromCache(modelCache, dataCache, token, callback); } @@ -493,29 +513,29 @@ class TestDriver12 : public V1_2::IDevice { // Like TestDriver, but implementing 1.1 class TestDriver11 : public V1_1::IDevice { public: - TestDriver11(const std::string& name, ErrorStatus errorStatus) + TestDriver11(const std::string& name, V1_3::ErrorStatus errorStatus) : mLatestDriver(new TestDriver13(name, errorStatus)) {} - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_1(_hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_1(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_1(model, preference, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); @@ -528,21 +548,21 @@ class TestDriver11 : public V1_1::IDevice { // Like TestDriver, but implementing 1.0 class TestDriver10 : public V1_0::IDevice { public: - TestDriver10(const std::string& name, ErrorStatus errorStatus) + TestDriver10(const std::string& name, V1_3::ErrorStatus errorStatus) : mLatestDriver(new TestDriver13(name, errorStatus)) {} - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } private: const sp<V1_3::IDevice> mLatestDriver; @@ -560,7 +580,7 @@ class TestCompilation : public WrapperCompilation { // Otherwise, don't bother to execute, and just send back // errorStatus (as the execution status, not the launch status). TestCompilation(const WrapperModel* model, const std::string& deviceName, - ErrorStatus errorStatus) { + V1_3::ErrorStatus errorStatus) { std::vector<std::shared_ptr<Device>> devices; auto device = DeviceManager::forTest_makeDriverDevice( deviceName, new DriverClass(deviceName, errorStatus)); @@ -613,7 +633,7 @@ class TestIntrospectionCompilation : public WrapperCompilation { template <class DriverClass> class ExecutionTestTemplate - : public ::testing::TestWithParam<std::tuple<ErrorStatus, Result, bool>> { + : public ::testing::TestWithParam<std::tuple<V1_3::ErrorStatus, WrapperResult, bool>> { public: ExecutionTestTemplate() : kName(toString(std::get<0>(GetParam()))), @@ -648,11 +668,11 @@ class ExecutionTestTemplate // sends back the actual execution status). Otherwise, don't // bother to execute, and just send back kForceErrorStatus (as the // execution status, not the launch status). - const ErrorStatus kForceErrorStatus; + const V1_3::ErrorStatus kForceErrorStatus; - // What result do we expect from the execution? (The Result + // What result do we expect from the execution? (The WrapperResult // equivalent of kForceErrorStatus.) - const Result kExpectResult; + const WrapperResult kExpectResult; // Whether mCompilation is created via Introspection API or not. const bool kUseIntrospectionAPI; @@ -663,8 +683,10 @@ class ExecutionTestTemplate void setInputOutput(WrapperExecution* execution) { mInputBuffer = kInputBuffer; mOutputBuffer = kOutputBufferInitial; - ASSERT_EQ(execution->setInput(0, &mInputBuffer, sizeof(mInputBuffer)), Result::NO_ERROR); - ASSERT_EQ(execution->setOutput(0, &mOutputBuffer, sizeof(mOutputBuffer)), Result::NO_ERROR); + ASSERT_EQ(execution->setInput(0, &mInputBuffer, sizeof(mInputBuffer)), + WrapperResult::NO_ERROR); + ASSERT_EQ(execution->setOutput(0, &mOutputBuffer, sizeof(mOutputBuffer)), + WrapperResult::NO_ERROR); } const float kInputBuffer = 3.14; @@ -683,7 +705,7 @@ class ExecutionTestTemplate uint32_t output = model.addOperand(&tensorType); model.addOperation(ANEURALNETWORKS_FLOOR, {input}, {output}); model.identifyInputsAndOutputs({input}, {output}); - assert(model.finish() == Result::NO_ERROR); + assert(model.finish() == WrapperResult::NO_ERROR); return model; } @@ -697,13 +719,13 @@ void ExecutionTestTemplate<DriverClass>::TestWait() { GTEST_SKIP(); } - ASSERT_EQ(mCompilation.finish(), Result::NO_ERROR); + ASSERT_EQ(mCompilation.finish(), WrapperResult::NO_ERROR); const auto getDimensionsWhileRunning = [](WrapperExecution& execution) { TestPreparedModelLatest::waitForExecutionToBegin(); // Cannot query dimensions while execution is running std::vector<uint32_t> dimensions; - EXPECT_EQ(execution.getOutputOperandDimensions(0, &dimensions), Result::BAD_STATE); + EXPECT_EQ(execution.getOutputOperandDimensions(0, &dimensions), WrapperResult::BAD_STATE); }; { @@ -712,21 +734,22 @@ void ExecutionTestTemplate<DriverClass>::TestWait() { ASSERT_NO_FATAL_FAILURE(setInputOutput(&execution)); TestPreparedModelLatest::pauseExecutions(true); WrapperEvent event; - ASSERT_EQ(execution.startCompute(&event), Result::NO_ERROR); + ASSERT_EQ(execution.startCompute(&event), WrapperResult::NO_ERROR); getDimensionsWhileRunning(execution); TestPreparedModelLatest::pauseExecutions(false); ASSERT_EQ(event.wait(), kExpectResult); - if (kExpectResult == Result::NO_ERROR) { + if (kExpectResult == WrapperResult::NO_ERROR) { ASSERT_EQ(mOutputBuffer, kOutputBufferExpected); } std::vector<uint32_t> dimensions; - if (kExpectResult == Result::NO_ERROR || - kExpectResult == Result::OUTPUT_INSUFFICIENT_SIZE) { + if (kExpectResult == WrapperResult::NO_ERROR || + kExpectResult == WrapperResult::OUTPUT_INSUFFICIENT_SIZE) { // Only one output operand, hardcoded as index 0. ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), kExpectResult); ASSERT_EQ(dimensions, kOutputDimensionsExpected); } else { - ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), Result::BAD_STATE); + ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), + WrapperResult::BAD_STATE); } } { @@ -738,17 +761,18 @@ void ExecutionTestTemplate<DriverClass>::TestWait() { getDimensionsWhileRunning(execution); TestPreparedModelLatest::pauseExecutions(false); run.join(); - if (kExpectResult == Result::NO_ERROR) { + if (kExpectResult == WrapperResult::NO_ERROR) { ASSERT_EQ(mOutputBuffer, kOutputBufferExpected); } std::vector<uint32_t> dimensions; - if (kExpectResult == Result::NO_ERROR || - kExpectResult == Result::OUTPUT_INSUFFICIENT_SIZE) { + if (kExpectResult == WrapperResult::NO_ERROR || + kExpectResult == WrapperResult::OUTPUT_INSUFFICIENT_SIZE) { // Only one output operand, hardcoded as index 0. ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), kExpectResult); ASSERT_EQ(dimensions, kOutputDimensionsExpected); } else { - ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), Result::BAD_STATE); + ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), + WrapperResult::BAD_STATE); } } { @@ -767,20 +791,21 @@ void ExecutionTestTemplate<DriverClass>::TestWait() { getDimensionsWhileRunning(execution); TestPreparedModelLatest::pauseExecutions(false); run.join(); - if (kExpectResult == Result::NO_ERROR) { + if (kExpectResult == WrapperResult::NO_ERROR) { ASSERT_EQ(mOutputBuffer, kOutputBufferExpected); } std::vector<uint32_t> dimensions; - if (kExpectResult == Result::NO_ERROR || - kExpectResult == Result::OUTPUT_INSUFFICIENT_SIZE) { + if (kExpectResult == WrapperResult::NO_ERROR || + kExpectResult == WrapperResult::OUTPUT_INSUFFICIENT_SIZE) { // Only one output operand, hardcoded as index 0. ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), kExpectResult); ASSERT_EQ(dimensions, kOutputDimensionsExpected); } else { - ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), Result::BAD_STATE); + ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), + WrapperResult::BAD_STATE); } } - if (kExpectResult != Result::OUTPUT_INSUFFICIENT_SIZE) { + if (kExpectResult != WrapperResult::OUTPUT_INSUFFICIENT_SIZE) { // computeWithDependencies doesn't support OUTPUT_INSUFFICIENT_SIZE SCOPED_TRACE("computeWithDependencies"); WrapperExecution execution(&mCompilation); @@ -796,32 +821,35 @@ void ExecutionTestTemplate<DriverClass>::TestWait() { getDimensionsWhileRunning(execution); TestPreparedModelLatest::pauseExecutions(false); run.join(); - if (kExpectResult == Result::NO_ERROR) { + if (kExpectResult == WrapperResult::NO_ERROR) { ASSERT_EQ(event.wait(), kExpectResult); ASSERT_EQ(mOutputBuffer, kOutputBufferExpected); } else { - ASSERT_EQ(event.wait(), Result::UNEXPECTED_NULL); + ASSERT_EQ(event.wait(), WrapperResult::UNEXPECTED_NULL); } std::vector<uint32_t> dimensions; - if (kExpectResult == Result::NO_ERROR) { + if (kExpectResult == WrapperResult::NO_ERROR) { // Only one output operand, hardcoded as index 0. ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), kExpectResult); ASSERT_EQ(dimensions, kOutputDimensionsExpected); } else { - ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), Result::BAD_STATE); + ASSERT_EQ(execution.getOutputOperandDimensions(0, &dimensions), + WrapperResult::BAD_STATE); } } } auto kTestValues = ::testing::Values( - std::make_tuple(ErrorStatus::NONE, Result::NO_ERROR, /* kUseIntrospectionAPI */ false), - std::make_tuple(ErrorStatus::DEVICE_UNAVAILABLE, Result::UNAVAILABLE_DEVICE, + std::make_tuple(V1_3::ErrorStatus::NONE, WrapperResult::NO_ERROR, + /* kUseIntrospectionAPI */ false), + std::make_tuple(V1_3::ErrorStatus::DEVICE_UNAVAILABLE, WrapperResult::UNAVAILABLE_DEVICE, /* kUseIntrospectionAPI */ false), - std::make_tuple(ErrorStatus::GENERAL_FAILURE, Result::OP_FAILED, + std::make_tuple(V1_3::ErrorStatus::GENERAL_FAILURE, WrapperResult::OP_FAILED, /* kUseIntrospectionAPI */ false), - std::make_tuple(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, Result::OUTPUT_INSUFFICIENT_SIZE, + std::make_tuple(V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, + WrapperResult::OUTPUT_INSUFFICIENT_SIZE, /* kUseIntrospectionAPI */ false), - std::make_tuple(ErrorStatus::INVALID_ARGUMENT, Result::BAD_DATA, + std::make_tuple(V1_3::ErrorStatus::INVALID_ARGUMENT, WrapperResult::BAD_DATA, /* kUseIntrospectionAPI */ false)); class ExecutionTest13 : public ExecutionTestTemplate<TestDriver13> {}; @@ -838,27 +866,29 @@ INSTANTIATE_TEST_SUITE_P(Flavor, ExecutionTest12, kTestValues); class ExecutionTest11 : public ExecutionTestTemplate<TestDriver11> {}; TEST_P(ExecutionTest11, Wait) { - if (kForceErrorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) return; + if (kForceErrorStatus == V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) return; TestWait(); } INSTANTIATE_TEST_SUITE_P(Flavor, ExecutionTest11, kTestValues); class ExecutionTest10 : public ExecutionTestTemplate<TestDriver10> {}; TEST_P(ExecutionTest10, Wait) { - if (kForceErrorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) return; + if (kForceErrorStatus == V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) return; TestWait(); } INSTANTIATE_TEST_SUITE_P(Flavor, ExecutionTest10, kTestValues); auto kIntrospectionTestValues = ::testing::Values( - std::make_tuple(ErrorStatus::NONE, Result::NO_ERROR, /* kUseIntrospectionAPI */ true), - std::make_tuple(ErrorStatus::DEVICE_UNAVAILABLE, Result::UNAVAILABLE_DEVICE, + std::make_tuple(V1_3::ErrorStatus::NONE, WrapperResult::NO_ERROR, + /* kUseIntrospectionAPI */ true), + std::make_tuple(V1_3::ErrorStatus::DEVICE_UNAVAILABLE, WrapperResult::UNAVAILABLE_DEVICE, /* kUseIntrospectionAPI */ true), - std::make_tuple(ErrorStatus::GENERAL_FAILURE, Result::OP_FAILED, + std::make_tuple(V1_3::ErrorStatus::GENERAL_FAILURE, WrapperResult::OP_FAILED, /* kUseIntrospectionAPI */ true), - std::make_tuple(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, Result::OUTPUT_INSUFFICIENT_SIZE, + std::make_tuple(V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, + WrapperResult::OUTPUT_INSUFFICIENT_SIZE, /* kUseIntrospectionAPI */ true), - std::make_tuple(ErrorStatus::INVALID_ARGUMENT, Result::BAD_DATA, + std::make_tuple(V1_3::ErrorStatus::INVALID_ARGUMENT, WrapperResult::BAD_DATA, /* kUseIntrospectionAPI */ true)); INSTANTIATE_TEST_SUITE_P(IntrospectionFlavor, ExecutionTest13, kIntrospectionTestValues); diff --git a/nn/runtime/test/TestExtensions.cpp b/nn/runtime/test/TestExtensions.cpp index f104854b9..da13073e2 100644 --- a/nn/runtime/test/TestExtensions.cpp +++ b/nn/runtime/test/TestExtensions.cpp @@ -32,7 +32,9 @@ using DeviceManager = ::android::nn::DeviceManager; using SampleDriver = ::android::nn::sample_driver::SampleDriver; using TypeManager = ::android::nn::TypeManager; -using namespace android::nn::hal; +namespace hardware = ::android::hardware; +namespace V1_0 = ::android::hardware::neuralnetworks::V1_0; +namespace V1_3 = ::android::hardware::neuralnetworks::V1_3; const char* kTestDriverName = "extensions-test-driver"; const char* kTestExtension1 = "vendor.test.one"; @@ -44,23 +46,24 @@ class TestDriver : public SampleDriver { TestDriver() : SampleDriver(kTestDriverName) {} ~TestDriver() override {} - Return<void> getSupportedExtensions(getSupportedExtensions_cb cb) override { + hardware::Return<void> getSupportedExtensions(getSupportedExtensions_cb cb) override { cb(V1_0::ErrorStatus::NONE, { {.name = kTestExtension1}, {.name = kTestExtension2}, {.name = kTestExtension3}, }); - return Void(); + return hardware::Void(); } - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { cb(V1_3::ErrorStatus::NONE, {/* Placeholder zero-filled capabilities. */}); - return Void(); + return hardware::Void(); } - Return<void> getSupportedOperations_1_3(const Model&, getSupportedOperations_1_3_cb) override { + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model&, + getSupportedOperations_1_3_cb) override { CHECK(false) << "not implemented"; - return Void(); + return hardware::Void(); } }; diff --git a/nn/runtime/test/TestFailingDriver.cpp b/nn/runtime/test/TestFailingDriver.cpp index 7d41ace20..d2e30a656 100644 --- a/nn/runtime/test/TestFailingDriver.cpp +++ b/nn/runtime/test/TestFailingDriver.cpp @@ -16,6 +16,7 @@ #include <gtest/gtest.h> +#include <algorithm> #include <memory> #include <vector> @@ -28,7 +29,6 @@ namespace android::nn { namespace { -using namespace hal; using sample_driver::SampleDriverPartial; using Result = test_wrapper::Result; using WrapperOperandType = test_wrapper::OperandType; @@ -50,20 +50,21 @@ class FailingTestDriver : public SampleDriverPartial { // EmptyOperationResolver causes execution to fail. FailingTestDriver() : SampleDriverPartial(kTestDriverName, &mEmptyOperationResolver) {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { cb(V1_3::ErrorStatus::NONE, - {.operandPerformance = {{.type = OperandType::TENSOR_FLOAT32, + {.operandPerformance = {{.type = V1_3::OperandType::TENSOR_FLOAT32, .info = {.execTime = 0.1, // Faster than CPU. .powerUsage = 0.1}}}}); - return Void(); + return hardware::Void(); } private: - std::vector<bool> getSupportedOperationsImpl(const Model& model) const override { + std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const override { std::vector<bool> supported(model.main.operations.size()); - std::transform( - model.main.operations.begin(), model.main.operations.end(), supported.begin(), - [](const Operation& operation) { return operation.type == OperationType::SQRT; }); + std::transform(model.main.operations.begin(), model.main.operations.end(), + supported.begin(), [](const V1_3::Operation& operation) { + return operation.type == V1_3::OperationType::SQRT; + }); return supported; } diff --git a/nn/runtime/test/TestIntrospectionControl.cpp b/nn/runtime/test/TestIntrospectionControl.cpp index 972619ef5..abb7e3306 100644 --- a/nn/runtime/test/TestIntrospectionControl.cpp +++ b/nn/runtime/test/TestIntrospectionControl.cpp @@ -16,6 +16,7 @@ #include <gtest/gtest.h> +#include <algorithm> #include <chrono> #include <iterator> #include <map> @@ -41,7 +42,10 @@ namespace { using namespace ::android; -using namespace nn::hal; +namespace V1_0 = ::android::hardware::neuralnetworks::V1_0; +namespace V1_1 = ::android::hardware::neuralnetworks::V1_1; +namespace V1_2 = ::android::hardware::neuralnetworks::V1_2; +namespace V1_3 = ::android::hardware::neuralnetworks::V1_3; using CompilationBuilder = nn::CompilationBuilder; using Device = nn::Device; @@ -63,40 +67,42 @@ using nn::convertToV1_3; template <typename T> using MQDescriptorSync = hardware::MQDescriptorSync<T>; -constexpr Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; -constexpr Timing kGoodUnfencedTiming = {.timeOnDevice = 123, .timeInDriver = 456}; -constexpr Timing kGoodFencedTiming = {.timeOnDevice = 23, .timeInDriver = 56}; +constexpr V1_2::Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; +constexpr V1_2::Timing kGoodUnfencedTiming = {.timeOnDevice = 123, .timeInDriver = 456}; +constexpr V1_2::Timing kGoodFencedTiming = {.timeOnDevice = 23, .timeInDriver = 56}; // This is an IDevice for testing purposes. The test driver has customized // getCapabilities_1_3 and getSupportedOperations_1_3. class TestDriver : public SampleDriver { public: - TestDriver(const char* name, Capabilities capabilities, const std::vector<bool>& supportedOps) + TestDriver(const char* name, V1_3::Capabilities capabilities, + const std::vector<bool>& supportedOps) : SampleDriver(name), mCapabilities(capabilities), mSupportedOps(supportedOps) {} ~TestDriver() override {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { cb(V1_3::ErrorStatus::NONE, mCapabilities); - return Void(); + return hardware::Void(); } - Return<void> getSupportedOperations_1_3(const Model& model, - getSupportedOperations_1_3_cb cb) override { + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model& model, + getSupportedOperations_1_3_cb cb) override { if (!android::nn::validateModel(model)) { cb(V1_3::ErrorStatus::INVALID_ARGUMENT, std::vector<bool>()); - return Void(); + return hardware::Void(); } const size_t count = model.main.operations.size(); std::vector<bool> supported(count); - std::transform( - model.main.operations.begin(), model.main.operations.end(), supported.begin(), - [this](Operation op) { return mSupportedOps[static_cast<int32_t>(op.type)]; }); + std::transform(model.main.operations.begin(), model.main.operations.end(), + supported.begin(), [this](V1_3::Operation op) { + return mSupportedOps[static_cast<int32_t>(op.type)]; + }); cb(V1_3::ErrorStatus::NONE, supported); - return Void(); + return hardware::Void(); } private: - Capabilities mCapabilities; + V1_3::Capabilities mCapabilities; std::vector<bool> mSupportedOps; }; @@ -119,7 +125,7 @@ class IntrospectionControlTest : public ::testing::Test { struct DeviceSpecification { DeviceSpecification(const std::string& name, float perf, std::vector<bool>& supportedOps) : mName(name), mSupportedOps(supportedOps) { - PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; + V1_0::PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; mCapabilities = { .relaxedFloat32toFloat16PerformanceScalar = perfInfo, .relaxedFloat32toFloat16PerformanceTensor = perfInfo, @@ -129,7 +135,7 @@ class IntrospectionControlTest : public ::testing::Test { .whilePerformance = perfInfo}; } std::string mName; - Capabilities mCapabilities; + V1_3::Capabilities mCapabilities; std::vector<bool> mSupportedOps; }; @@ -383,14 +389,14 @@ std::ostream& operator<<(std::ostream& os, Success success) { // Returns (unfenced timing, fenced timing). // Not for PASS_CPU. -std::pair<Timing, Timing> getExpectedTiming(Success s, bool fencedExecution) { +std::pair<V1_2::Timing, V1_2::Timing> getExpectedTiming(Success s, bool fencedExecution) { CHECK_NE(s, Success::PASS_CPU); if (!hasBit(s, Success::PASS_BIT)) { return {kBadTiming, kBadTiming}; } - std::pair<Timing, Timing> result; + std::pair<V1_2::Timing, V1_2::Timing> result; result.first.timeOnDevice = hasBit(s, Success::PASS_UNFENCED_DEVICE_BIT) ? kGoodUnfencedTiming.timeOnDevice : UINT64_MAX; @@ -416,12 +422,12 @@ std::pair<Timing, Timing> getExpectedTiming(Success s, bool fencedExecution) { class TestPreparedModelLatest : public SamplePreparedModel { public: TestPreparedModelLatest(const HidlModel& model, const SampleDriver* driver, Success success) - : SamplePreparedModel(model, driver, ExecutionPreference::FAST_SINGLE_ANSWER, uid_t{}, - kDefaultPriority), + : SamplePreparedModel(model, driver, V1_1::ExecutionPreference::FAST_SINGLE_ANSWER, uid_t{}, + nn::kDefaultPriority13), mSuccess(success) {} - Return<V1_0::ErrorStatus> execute(const V1_0::Request&, - const sp<V1_0::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request&, const sp<V1_0::IExecutionCallback>& callback) override { switch (mSuccess) { case Success::PASS_NEITHER: std::thread([callback] { @@ -445,9 +451,10 @@ class TestPreparedModelLatest : public SamplePreparedModel { } } - Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request&, MeasureTiming measure, - const sp<V1_2::IExecutionCallback>& callback) override { - EXPECT_EQ(measure, MeasureTiming::YES); + hardware::Return<V1_0::ErrorStatus> execute_1_2( + const V1_0::Request&, V1_2::MeasureTiming measure, + const sp<V1_2::IExecutionCallback>& callback) override { + EXPECT_EQ(measure, V1_2::MeasureTiming::YES); switch (mSuccess) { case Success::PASS_NEITHER: case Success::PASS_DEVICE: @@ -475,17 +482,18 @@ class TestPreparedModelLatest : public SamplePreparedModel { } } - Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request&, MeasureTiming measure, - const OptionalTimePoint&, const OptionalTimeoutDuration&, - const sp<V1_3::IExecutionCallback>& callback) override { + hardware::Return<V1_3::ErrorStatus> execute_1_3( + const V1_3::Request&, V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + const sp<V1_3::IExecutionCallback>& callback) override { // Use a placeholder V1_0::Request because execute_1_2 ignores request entirely. const V1_0::ErrorStatus status = execute_1_2(V1_0::Request{}, measure, callback); return convertToV1_3(status); } - Return<void> executeSynchronously(const V1_0::Request&, MeasureTiming measure, - executeSynchronously_cb cb) override { - EXPECT_EQ(measure, MeasureTiming::YES); + hardware::Return<void> executeSynchronously(const V1_0::Request&, V1_2::MeasureTiming measure, + executeSynchronously_cb cb) override { + EXPECT_EQ(measure, V1_2::MeasureTiming::YES); switch (mSuccess) { case Success::PASS_NEITHER: case Success::PASS_DEVICE: @@ -493,7 +501,7 @@ class TestPreparedModelLatest : public SamplePreparedModel { case Success::PASS_BOTH: dummyExecution(); cb(V1_0::ErrorStatus::NONE, {}, getExpectedTiming(mSuccess, false).first); - return Void(); + return hardware::Void(); case Success::FAIL_WAIT: // While this is a synchronous execution method, the NNAPI // runtime may call it even for asynchronous execution, so we @@ -503,19 +511,22 @@ class TestPreparedModelLatest : public SamplePreparedModel { case Success::FAIL_LAUNCH: dummyExecution(); cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kBadTiming); - return Void(); + return hardware::Void(); default: ADD_FAILURE() << "Unexpected Success kind"; cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kBadTiming); - return Void(); + return hardware::Void(); } } - Return<void> executeSynchronously_1_3(const V1_3::Request&, MeasureTiming measure, - const OptionalTimePoint&, const OptionalTimeoutDuration&, - executeSynchronously_1_3_cb cb) override { + hardware::Return<void> executeSynchronously_1_3(const V1_3::Request&, + V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + executeSynchronously_1_3_cb cb) override { const auto wrappedCb = [&cb](V1_0::ErrorStatus status, - const hidl_vec<OutputShape>& outputShapes, Timing timing) { + const hardware::hidl_vec<V1_2::OutputShape>& outputShapes, + V1_2::Timing timing) { cb(convertToV1_3(status), outputShapes, timing); }; // Use a placeholder V1_0::Request because executeSynchronously ignores request entirely. @@ -525,7 +536,7 @@ class TestPreparedModelLatest : public SamplePreparedModel { // ExecutionBurstServer::create has an overload that will use // IPreparedModel::executeSynchronously(), so we can rely on that, rather // than having to implement ExecutionBurstServer::IExecutorWithCache. - Return<void> configureExecutionBurst( + hardware::Return<void> configureExecutionBurst( const sp<V1_2::IBurstCallback>& callback, const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, @@ -534,21 +545,26 @@ class TestPreparedModelLatest : public SamplePreparedModel { callback, requestChannel, resultChannel, this, std::chrono::microseconds{0}); cb(burst == nullptr ? V1_0::ErrorStatus::GENERAL_FAILURE : V1_0::ErrorStatus::NONE, burst); - return Void(); + return hardware::Void(); } - Return<void> executeFenced(const Request&, const hidl_vec<hidl_handle>&, MeasureTiming measure, - const OptionalTimePoint&, const OptionalTimeoutDuration&, - const OptionalTimeoutDuration&, executeFenced_cb callback) override { - EXPECT_EQ(measure, MeasureTiming::YES); + hardware::Return<void> executeFenced(const V1_3::Request&, + const hardware::hidl_vec<hardware::hidl_handle>&, + V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint&, + const V1_3::OptionalTimeoutDuration&, + const V1_3::OptionalTimeoutDuration&, + executeFenced_cb callback) override { + EXPECT_EQ(measure, V1_2::MeasureTiming::YES); if (hasBit(mSuccess, Success::PASS_BIT)) { dummyExecution(); const auto expectedTiming = getExpectedTiming(mSuccess, true); sp<SampleFencedExecutionCallback> fencedExecutionCallback = new SampleFencedExecutionCallback(expectedTiming.first, expectedTiming.second, V1_3::ErrorStatus::NONE); - callback(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), fencedExecutionCallback); - return Void(); + callback(V1_3::ErrorStatus::NONE, hardware::hidl_handle(nullptr), + fencedExecutionCallback); + return hardware::Void(); } switch (mSuccess) { case Success::FAIL_WAIT: @@ -559,11 +575,12 @@ class TestPreparedModelLatest : public SamplePreparedModel { FALLTHROUGH_INTENDED; case Success::FAIL_LAUNCH: dummyExecution(); - callback(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr); - return Void(); + callback(V1_3::ErrorStatus::GENERAL_FAILURE, hardware::hidl_handle(nullptr), + nullptr); + return hardware::Void(); default: ADD_FAILURE() << "Unexpected Success kind"; - return Void(); + return hardware::Void(); } } @@ -607,22 +624,24 @@ class TestPreparedModel12 : public V1_2::IPreparedModel { TestPreparedModel12(const HidlModel& model, const SampleDriver* driver, Success success) : mLatestPreparedModel(new TestPreparedModelLatest(model, driver, success)) {} - Return<V1_0::ErrorStatus> execute(const V1_0::Request& request, - const sp<V1_0::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) override { return mLatestPreparedModel->execute(request, callback); } - Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request& request, MeasureTiming measure, - const sp<V1_2::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute_1_2( + const V1_0::Request& request, V1_2::MeasureTiming measure, + const sp<V1_2::IExecutionCallback>& callback) override { return mLatestPreparedModel->execute_1_2(request, measure, callback); } - Return<void> executeSynchronously(const V1_0::Request& request, MeasureTiming measure, - executeSynchronously_cb cb) override { + hardware::Return<void> executeSynchronously(const V1_0::Request& request, + V1_2::MeasureTiming measure, + executeSynchronously_cb cb) override { return mLatestPreparedModel->executeSynchronously(request, measure, cb); } - Return<void> configureExecutionBurst( + hardware::Return<void> configureExecutionBurst( const sp<V1_2::IBurstCallback>& callback, const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, @@ -632,7 +651,7 @@ class TestPreparedModel12 : public V1_2::IPreparedModel { } private: - const sp<IPreparedModel> mLatestPreparedModel; + const sp<V1_3::IPreparedModel> mLatestPreparedModel; }; // Like TestPreparedModelLatest, but implementing 1.0 @@ -641,13 +660,13 @@ class TestPreparedModel10 : public V1_0::IPreparedModel { TestPreparedModel10(const HidlModel& model, const SampleDriver* driver, Success success) : mLatestPreparedModel(new TestPreparedModelLatest(model, driver, success)) {} - Return<V1_0::ErrorStatus> execute(const V1_0::Request& request, - const sp<V1_0::IExecutionCallback>& callback) override { + hardware::Return<V1_0::ErrorStatus> execute( + const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback) override { return mLatestPreparedModel->execute(request, callback); } private: - const sp<IPreparedModel> mLatestPreparedModel; + const sp<V1_3::IPreparedModel> mLatestPreparedModel; }; // Behaves like SampleDriver, except that it produces customized IPrepareModel. @@ -656,31 +675,31 @@ class TestDriver13 : public SampleDriver { TestDriver13(const std::string& name, Success success) : SampleDriver(name.c_str()), mSuccess(success) {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb _hidl_cb) override { android::nn::initVLogMask(); - const PerformanceInfo kPerf = {.execTime = 0.75f, .powerUsage = 0.75f}; - Capabilities capabilities = { + const V1_0::PerformanceInfo kPerf = {.execTime = 0.75f, .powerUsage = 0.75f}; + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = kPerf, .relaxedFloat32toFloat16PerformanceTensor = kPerf, .operandPerformance = nn::nonExtensionOperandPerformance<nn::HalVersion::V1_3>(kPerf)}; _hidl_cb(V1_3::ErrorStatus::NONE, capabilities); - return Void(); + return hardware::Void(); } - Return<void> getSupportedOperations_1_3(const HidlModel& model, - getSupportedOperations_1_3_cb cb) override { + hardware::Return<void> getSupportedOperations_1_3(const HidlModel& model, + getSupportedOperations_1_3_cb cb) override { if (nn::validateModel(model)) { std::vector<bool> supported(model.main.operations.size(), true); cb(V1_3::ErrorStatus::NONE, supported); } else { cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}); } - return Void(); + return hardware::Void(); } - Return<void> getSupportedOperations_1_2(const V1_2::Model& model, - getSupportedOperations_1_2_cb cb) override { + hardware::Return<void> getSupportedOperations_1_2(const V1_2::Model& model, + getSupportedOperations_1_2_cb cb) override { if (nn::validateModel(model)) { std::vector<bool> supported(model.operations.size(), true); cb(V1_0::ErrorStatus::NONE, supported); @@ -688,39 +707,41 @@ class TestDriver13 : public SampleDriver { std::vector<bool> supported; cb(V1_0::ErrorStatus::INVALID_ARGUMENT, supported); } - return Void(); + return hardware::Void(); } - Return<V1_3::ErrorStatus> prepareModel_1_3( - const HidlModel& model, ExecutionPreference, Priority, const OptionalTimePoint&, - const hidl_vec<hidl_handle>&, const hidl_vec<hidl_handle>&, const CacheToken&, + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const HidlModel& model, V1_1::ExecutionPreference, V1_3::Priority, + const V1_3::OptionalTimePoint&, const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const nn::HalCacheToken&, const sp<V1_3::IPreparedModelCallback>& callback) override { callback->notify_1_3(V1_3::ErrorStatus::NONE, new TestPreparedModel13(model, this, mSuccess)); return V1_3::ErrorStatus::NONE; } - Return<V1_0::ErrorStatus> prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference, const hidl_vec<hidl_handle>&, - const hidl_vec<hidl_handle>&, const CacheToken&, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference, + const hardware::hidl_vec<hardware::hidl_handle>&, + const hardware::hidl_vec<hardware::hidl_handle>&, const nn::HalCacheToken&, const sp<V1_2::IPreparedModelCallback>& callback) override { callback->notify_1_2(V1_0::ErrorStatus::NONE, new TestPreparedModel12(nn::convertToV1_3(model), this, mSuccess)); return V1_0::ErrorStatus::NONE; } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference, const sp<V1_0::IPreparedModelCallback>& callback) override { callback->notify(V1_0::ErrorStatus::NONE, new TestPreparedModel10(nn::convertToV1_3(model), this, mSuccess)); return V1_0::ErrorStatus::NONE; } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback) override { - return prepareModel_1_1(nn::convertToV1_1(model), ExecutionPreference::FAST_SINGLE_ANSWER, - callback); + return prepareModel_1_1(nn::convertToV1_1(model), + V1_1::ExecutionPreference::FAST_SINGLE_ANSWER, callback); } private: @@ -732,27 +753,27 @@ class TestDriver11 : public V1_1::IDevice { public: TestDriver11(const std::string& name, Success success) : mLatestDriver(new TestDriver13(name, success)) {} - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_1(_hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_1(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_1(model, preference, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); diff --git a/nn/runtime/test/TestMemoryDomain.cpp b/nn/runtime/test/TestMemoryDomain.cpp index 06418e5af..35a826ab8 100644 --- a/nn/runtime/test/TestMemoryDomain.cpp +++ b/nn/runtime/test/TestMemoryDomain.cpp @@ -34,20 +34,22 @@ #include "TestUtils.h" using namespace android::nn; -using namespace hal; -using Result = test_wrapper::Result; +namespace hardware = android::hardware; +using WrapperResult = test_wrapper::Result; using Type = test_wrapper::Type; +using android::sp; namespace { // A buffer for test that does nothing. -class TestBuffer : public IBuffer { +class TestBuffer : public V1_3::IBuffer { public: - Return<ErrorStatus> copyTo(const hidl_memory&) override { - return ErrorStatus::DEVICE_UNAVAILABLE; + hardware::Return<V1_3::ErrorStatus> copyTo(const hardware::hidl_memory&) override { + return V1_3::ErrorStatus::DEVICE_UNAVAILABLE; } - Return<ErrorStatus> copyFrom(const hidl_memory&, const hidl_vec<uint32_t>&) override { - return ErrorStatus::DEVICE_UNAVAILABLE; + hardware::Return<V1_3::ErrorStatus> copyFrom(const hardware::hidl_memory&, + const hardware::hidl_vec<uint32_t>&) override { + return V1_3::ErrorStatus::DEVICE_UNAVAILABLE; } }; @@ -73,64 +75,67 @@ std::ostream& operator<<(std::ostream& os, AllocateReturn allocateReturn) { class TestDriverLatest : public sample_driver::SampleDriver { public: - TestDriverLatest(const char* name, std::set<OperationType> supportedOperations, + TestDriverLatest(const char* name, std::set<V1_3::OperationType> supportedOperations, AllocateReturn allocateReturn) : SampleDriver(name), kSupportedOperations(std::move(supportedOperations)), kAllocateReturn(allocateReturn) {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { android::nn::initVLogMask(); // Faster than cpu. - const PerformanceInfo kPerf = {.execTime = 0.1, .powerUsage = 0.1}; - const Capabilities capabilities = { + const V1_0::PerformanceInfo kPerf = {.execTime = 0.1, .powerUsage = 0.1}; + const V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = kPerf, .relaxedFloat32toFloat16PerformanceTensor = kPerf, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>(kPerf), .ifPerformance = kPerf, .whilePerformance = kPerf}; - cb(ErrorStatus::NONE, capabilities); - return Void(); + cb(V1_3::ErrorStatus::NONE, capabilities); + return hardware::Void(); } - Return<void> getSupportedOperations_1_3(const Model& model, - getSupportedOperations_1_3_cb cb) override { + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model& model, + getSupportedOperations_1_3_cb cb) override { // The tests will never use a referenced model. CHECK(model.referenced.size() == 0); std::vector<bool> supported(model.main.operations.size(), false); - std::transform( - model.main.operations.begin(), model.main.operations.end(), supported.begin(), - [this](const Operation& op) { return kSupportedOperations.count(op.type) > 0; }); - cb(ErrorStatus::NONE, supported); - return Void(); + std::transform(model.main.operations.begin(), model.main.operations.end(), + supported.begin(), [this](const V1_3::Operation& op) { + return kSupportedOperations.count(op.type) > 0; + }); + cb(V1_3::ErrorStatus::NONE, supported); + return hardware::Void(); } - Return<void> allocate(const BufferDesc&, const hidl_vec<sp<IPreparedModel>>&, - const hidl_vec<BufferRole>&, const hidl_vec<BufferRole>&, - allocate_cb cb) override { + hardware::Return<void> allocate(const V1_3::BufferDesc&, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>&, + const hardware::hidl_vec<V1_3::BufferRole>&, + const hardware::hidl_vec<V1_3::BufferRole>&, + allocate_cb cb) override { switch (kAllocateReturn) { case AllocateReturn::OK: - cb(ErrorStatus::NONE, new TestBuffer(), mValidBufferToken++); - return Void(); + cb(V1_3::ErrorStatus::NONE, new TestBuffer(), mValidBufferToken++); + return hardware::Void(); case AllocateReturn::BAD_IBUFFER: - cb(ErrorStatus::NONE, nullptr, mValidBufferToken++); - return Void(); + cb(V1_3::ErrorStatus::NONE, nullptr, mValidBufferToken++); + return hardware::Void(); case AllocateReturn::BAD_TOKEN: - cb(ErrorStatus::NONE, new TestBuffer(), 0); - return Void(); + cb(V1_3::ErrorStatus::NONE, new TestBuffer(), 0); + return hardware::Void(); case AllocateReturn::BAD_STATUS: - cb(ErrorStatus::GENERAL_FAILURE, new TestBuffer(), mValidBufferToken++); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, new TestBuffer(), mValidBufferToken++); + return hardware::Void(); case AllocateReturn::NOT_SUPPORTED: - cb(ErrorStatus::GENERAL_FAILURE, nullptr, 0); - return Void(); + cb(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, 0); + return hardware::Void(); } LOG(FATAL) << "Invalid AllocateReturn code " << static_cast<int>(kAllocateReturn); - return Void(); + return hardware::Void(); } private: - const std::set<OperationType> kSupportedOperations; + const std::set<V1_3::OperationType> kSupportedOperations; const AllocateReturn kAllocateReturn; uint32_t mValidBufferToken = 1; }; @@ -160,7 +165,7 @@ void createTestModel(test_wrapper::Model* model) { model->addOperation(ANEURALNETWORKS_SUB, {input1, input2, act}, {temp}); model->addOperation(ANEURALNETWORKS_MUL, {output0, temp, act}, {output1}); model->identifyInputsAndOutputs({input0, input1, input2}, {output0, output1}); - EXPECT_EQ(model->finish(), Result::NO_ERROR); + EXPECT_EQ(model->finish(), WrapperResult::NO_ERROR); } class MemoryDomainTestBase : public ::testing::Test { @@ -199,14 +204,14 @@ class MemoryDomainTestBase : public ::testing::Test { std::vector<const ANeuralNetworksDevice*> devices(deviceNames.size()); std::transform(deviceNames.begin(), deviceNames.end(), devices.begin(), [&deviceMap](const std::string& name) { return deviceMap.at(name); }); - Result result; + WrapperResult result; std::tie(result, compilation) = test_wrapper::Compilation::createForDevices(&mModel, devices); - EXPECT_EQ(result, Result::NO_ERROR); + EXPECT_EQ(result, WrapperResult::NO_ERROR); } else { compilation = test_wrapper::Compilation(&mModel); } - EXPECT_EQ(compilation.finish(), Result::NO_ERROR); + EXPECT_EQ(compilation.finish(), WrapperResult::NO_ERROR); return compilation; } @@ -245,7 +250,8 @@ class MemoryDomainTest : public MemoryDomainTestBase, public ::testing::WithParamInterface<MemoryDomainTestParam> { protected: // If kUseV1_2Driver, allocateReturn must be AllocateReturn::NOT_SUPPORTED. - void createAndRegisterDriver(const char* name, std::set<OperationType> supportedOperations, + void createAndRegisterDriver(const char* name, + std::set<V1_3::OperationType> supportedOperations, AllocateReturn allocateReturn) { sp<V1_0::IDevice> driver; if (kUseV1_2Driver) { @@ -275,9 +281,10 @@ class MemoryDomainTest : public MemoryDomainTestBase, // Test device memory allocation on a compilation with only a single partition. TEST_P(MemoryDomainTest, SinglePartition) { - createAndRegisterDriver("test_driver", - {OperationType::ADD, OperationType::SUB, OperationType::MUL}, - kAllocateReturn); + createAndRegisterDriver( + "test_driver", + {V1_3::OperationType::ADD, V1_3::OperationType::SUB, V1_3::OperationType::MUL}, + kAllocateReturn); auto compilation = createCompilation({"test_driver"}); ASSERT_NE(compilation.getHandle(), nullptr); @@ -285,7 +292,7 @@ TEST_P(MemoryDomainTest, SinglePartition) { if (kAllocateReturn == AllocateReturn::OK) { // The memory should be backed by the IBuffer returned from the driver. ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - const Memory* m = reinterpret_cast<const Memory*>(memory.get()); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory.get()); ASSERT_NE(m, nullptr); EXPECT_NE(m->getIBuffer(), nullptr); } else { @@ -295,7 +302,7 @@ TEST_P(MemoryDomainTest, SinglePartition) { } else { // The memory should fallback to ashmem or blob ahwb based on the driver version. ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - const Memory* m = reinterpret_cast<const Memory*>(memory.get()); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory.get()); ASSERT_NE(m, nullptr); EXPECT_EQ(m->getIBuffer(), nullptr); const auto& hidlMemory = m->getHidlMemory(); @@ -311,9 +318,9 @@ TEST_P(MemoryDomainTest, SinglePartition) { // Test device memory allocation on a compilation with multiple partitions. TEST_P(MemoryDomainTest, MultiplePartitions) { - createAndRegisterDriver("test_driver_add", {OperationType::ADD}, kAllocateReturn); - createAndRegisterDriver("test_driver_sub", {OperationType::SUB}, kAllocateReturn); - createAndRegisterDriver("test_driver_mul", {OperationType::MUL}, kAllocateReturn); + createAndRegisterDriver("test_driver_add", {V1_3::OperationType::ADD}, kAllocateReturn); + createAndRegisterDriver("test_driver_sub", {V1_3::OperationType::SUB}, kAllocateReturn); + createAndRegisterDriver("test_driver_mul", {V1_3::OperationType::MUL}, kAllocateReturn); auto compilation = createCompilation({"test_driver_add", "test_driver_sub", "test_driver_mul"}); ASSERT_NE(compilation.getHandle(), nullptr); @@ -323,7 +330,7 @@ TEST_P(MemoryDomainTest, MultiplePartitions) { if (kAllocateReturn == AllocateReturn::OK) { // The memory should be backed by the IBuffer returned from the driver. ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - const Memory* m = reinterpret_cast<const Memory*>(memory.get()); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory.get()); ASSERT_NE(m, nullptr); EXPECT_NE(m->getIBuffer(), nullptr); } else { @@ -333,7 +340,7 @@ TEST_P(MemoryDomainTest, MultiplePartitions) { } else { // The memory should fallback to ashmem or blob ahwb based on the driver version. ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - const Memory* m = reinterpret_cast<const Memory*>(memory.get()); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory.get()); ASSERT_NE(m, nullptr); EXPECT_EQ(m->getIBuffer(), nullptr); const auto& hidlMemory = m->getHidlMemory(); @@ -357,7 +364,7 @@ TEST_P(MemoryDomainTest, MultiplePartitions) { } else { // The memory should fallback to ashmem or blob ahwb based on the driver version. ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - const Memory* m = reinterpret_cast<const Memory*>(memory.get()); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory.get()); ASSERT_NE(m, nullptr); EXPECT_EQ(m->getIBuffer(), nullptr); const auto& hidlMemory = m->getHidlMemory(); @@ -380,7 +387,7 @@ TEST_P(MemoryDomainTest, MultiplePartitions) { } else { // The memory should fallback to ashmem or blob ahwb based on the driver version. ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - const Memory* m = reinterpret_cast<const Memory*>(memory.get()); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory.get()); ASSERT_NE(m, nullptr); EXPECT_EQ(m->getIBuffer(), nullptr); const auto& hidlMemory = m->getHidlMemory(); @@ -396,9 +403,10 @@ TEST_P(MemoryDomainTest, MultiplePartitions) { // Test device memory allocation with dynamic shape. TEST_P(MemoryDomainTest, DynamicShape) { - createAndRegisterDriver("test_driver", - {OperationType::ADD, OperationType::SUB, OperationType::MUL}, - kAllocateReturn); + createAndRegisterDriver( + "test_driver", + {V1_3::OperationType::ADD, V1_3::OperationType::SUB, V1_3::OperationType::MUL}, + kAllocateReturn); auto compilation = createCompilation({"test_driver"}); ASSERT_NE(compilation.getHandle(), nullptr); @@ -406,7 +414,7 @@ TEST_P(MemoryDomainTest, DynamicShape) { if (kAllocateReturn == AllocateReturn::OK) { // The memory should be backed by the IBuffer returned from the driver. ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR); - const Memory* m = reinterpret_cast<const Memory*>(memory.get()); + const RuntimeMemory* m = reinterpret_cast<const RuntimeMemory*>(memory.get()); ASSERT_NE(m, nullptr); EXPECT_NE(m->getIBuffer(), nullptr); } else { diff --git a/nn/runtime/test/TestPartitioning.cpp b/nn/runtime/test/TestPartitioning.cpp index d85717ce7..939612a78 100644 --- a/nn/runtime/test/TestPartitioning.cpp +++ b/nn/runtime/test/TestPartitioning.cpp @@ -145,7 +145,11 @@ namespace { -using namespace android::nn::hal; +namespace hardware = android::hardware; +namespace V1_0 = ::android::hardware::neuralnetworks::V1_0; +namespace V1_1 = ::android::hardware::neuralnetworks::V1_1; +namespace V1_2 = ::android::hardware::neuralnetworks::V1_2; +namespace V1_3 = ::android::hardware::neuralnetworks::V1_3; using CompilationBuilder = ::android::nn::CompilationBuilder; using Deadline = ::android::nn::Deadline; using Device = ::android::nn::Device; @@ -154,10 +158,13 @@ using ExecutePreference = ::android::nn::test_wrapper::ExecutePreference; using ExecutePriority = ::android::nn::test_wrapper::ExecutePriority; using ExecutionPlan = ::android::nn::ExecutionPlan; using ExecutionStep = ::android::nn::ExecutionStep; +using HalCacheToken = ::android::nn::HalCacheToken; using HalVersion = ::android::nn::HalVersion; using HidlModel = V1_3::Model; using LogicalStep = ::android::nn::LogicalStep; using ModelBuilder = ::android::nn::ModelBuilder; +using Operand = ::android::nn::Operand; +using Operation = ::android::nn::Operation; using Result = ::android::nn::test_wrapper::Result; using SampleDriver = ::android::nn::sample_driver::SampleDriver; using WrapperCompilation = ::android::nn::test_wrapper::Compilation; @@ -166,9 +173,10 @@ using WrapperModel = ::android::nn::test_wrapper::Model; using WrapperOperandType = ::android::nn::test_wrapper::OperandType; using WrapperSymmPerChannelQuantParams = ::android::nn::test_wrapper::SymmPerChannelQuantParams; using WrapperType = ::android::nn::test_wrapper::Type; +using android::sp; -Capabilities makeCapabilities(float perf) { - PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; +V1_3::Capabilities makeCapabilities(float perf) { + V1_0::PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; return {.relaxedFloat32toFloat16PerformanceScalar = perfInfo, .relaxedFloat32toFloat16PerformanceTensor = perfInfo, .operandPerformance = @@ -177,12 +185,12 @@ Capabilities makeCapabilities(float perf) { .whilePerformance = perfInfo}; }; -void update(Capabilities* capabilities, OperandType type, float perf) { - PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; +void update(V1_3::Capabilities* capabilities, V1_3::OperandType type, float perf) { + V1_0::PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; ::android::nn::update(&capabilities->operandPerformance, type, perfInfo); } -float lookupExecTime(const Capabilities& capabilities, OperandType type) { +float lookupExecTime(const V1_3::Capabilities& capabilities, V1_3::OperandType type) { return ::android::nn::lookup(capabilities.operandPerformance, type).execTime; } @@ -214,16 +222,16 @@ const uint32_t kFirstEncodingHARD_SWISH = kLastEncodingV1_2 + 1; const uint32_t kFirstEncodingV1_3 = kFirstEncodingHARD_SWISH; const uint32_t kLastEncodingV1_3 = kFirstEncodingHARD_SWISH; -const std::map<OperationType, uint32_t> operationToFirstEncoding = { - {OperationType::ADD, kFirstEncodingADD}, - {OperationType::MUL, kFirstEncodingMUL}, - {OperationType::DIV, kFirstEncodingDIV}, - {OperationType::SUB, kFirstEncodingSUB}, - {OperationType::MAXIMUM, kFirstEncodingMAXIMUM}, - {OperationType::MINIMUM, kFirstEncodingMINIMUM}, - {OperationType::POW, kFirstEncodingPOW}, - {OperationType::PRELU, kFirstEncodingPRELU}, - {OperationType::HARD_SWISH, kFirstEncodingHARD_SWISH}, +const std::map<V1_3::OperationType, uint32_t> operationToFirstEncoding = { + {V1_3::OperationType::ADD, kFirstEncodingADD}, + {V1_3::OperationType::MUL, kFirstEncodingMUL}, + {V1_3::OperationType::DIV, kFirstEncodingDIV}, + {V1_3::OperationType::SUB, kFirstEncodingSUB}, + {V1_3::OperationType::MAXIMUM, kFirstEncodingMAXIMUM}, + {V1_3::OperationType::MINIMUM, kFirstEncodingMINIMUM}, + {V1_3::OperationType::POW, kFirstEncodingPOW}, + {V1_3::OperationType::PRELU, kFirstEncodingPRELU}, + {V1_3::OperationType::HARD_SWISH, kFirstEncodingHARD_SWISH}, }; // Sorted in reverse order (std::greater) so that we can use map::lower_bound to @@ -244,20 +252,20 @@ const std::map<uint32_t, std::pair<uint32_t, bool>, std::greater<>> firstEncodin // Look up the operation with the specified index in a graph, and return the // operation encoding; or, if for some reason this is not one of the encoded // operations, then return kBadOperation. -uint32_t lookupOperation(std::function<const Operation&(uint32_t)> getOperation, - std::function<const Operand&(uint32_t)> getOperand, +uint32_t lookupOperation(std::function<const V1_3::Operation&(uint32_t)> getOperation, + std::function<const V1_3::Operand&(uint32_t)> getOperand, std::function<const uint8_t*(uint32_t)> getValue, uint32_t operationIndex) { - const Operation& operation = getOperation(operationIndex); + const V1_3::Operation& operation = getOperation(operationIndex); switch (operation.type) { - case OperationType::ADD: - case OperationType::MUL: - case OperationType::DIV: - case OperationType::SUB: { + case V1_3::OperationType::ADD: + case V1_3::OperationType::MUL: + case V1_3::OperationType::DIV: + case V1_3::OperationType::SUB: { // input2 is the fused activation function - const Operand& input2 = getOperand(operation.inputs[2]); - if ((input2.type == OperandType::INT32) && - (input2.lifetime == OperandLifeTime::CONSTANT_COPY)) { + const V1_3::Operand& input2 = getOperand(operation.inputs[2]); + if ((input2.type == V1_3::OperandType::INT32) && + (input2.lifetime == V1_3::OperandLifeTime::CONSTANT_COPY)) { int32_t value; CHECK_EQ(sizeof(value), input2.location.length); memcpy(&value, getValue(input2.location.offset), input2.location.length); @@ -276,11 +284,15 @@ uint32_t lookupOperation(std::function<const Operation&(uint32_t)> getOperation, return kBadOperation; } -uint32_t lookupOperation(const HidlModel& model, const Subgraph& subgraph, +uint32_t lookupOperation(const HidlModel& model, const V1_3::Subgraph& subgraph, uint32_t operationIndex) { return lookupOperation( - [&subgraph](uint32_t index) -> const Operation& { return subgraph.operations[index]; }, - [&subgraph](uint32_t index) -> const Operand& { return subgraph.operands[index]; }, + [&subgraph](uint32_t index) -> const V1_3::Operation& { + return subgraph.operations[index]; + }, + [&subgraph](uint32_t index) -> const V1_3::Operand& { + return subgraph.operands[index]; + }, [&model](uint32_t offset) { return &model.operandValues[offset]; }, operationIndex); } @@ -288,12 +300,11 @@ uint32_t lookupOperation(const HidlModel& model, const Subgraph& subgraph, // This is a debugging utility function void dump(const char* name, const ModelBuilder* model) { const HidlModel hidlModel = model->makeHidlModel(); - std::cout << name << ": " << toString(hidlModel) << std::endl; - std::cout << "inputs: " << toString(hidlModel.main.inputIndexes) << std::endl; - std::cout << "outputs: " << toString(hidlModel.main.outputIndexes) << std::endl; + std::cout << name << ": " << hidlModel << std::endl; + std::cout << "inputs: " << hidlModel.main.inputIndexes << std::endl; + std::cout << "outputs: " << hidlModel.main.outputIndexes << std::endl; for (size_t i = 0, e = hidlModel.main.operations.size(); i < e; i++) { - std::cout << "operation[" << i << "]: " << toString(hidlModel.main.operations[i]) - << std::endl; + std::cout << "operation[" << i << "]: " << hidlModel.main.operations[i] << std::endl; } } #endif @@ -313,37 +324,39 @@ class PartitioningDriver : public SampleDriver { OEMYes, // accepted by getSupportedOperations and prepareModel }; - PartitioningDriver(const char* name, const char* version, Capabilities capabilities, + PartitioningDriver(const char* name, const char* version, V1_3::Capabilities capabilities, uint32_t operationMask, OEM oem = OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : SampleDriver(name), mVersionString(version), mCapabilities(capabilities), mOperationMask(operationMask), mOEM(oem), mOperationTypes(std::move(operationTypes)) { - CHECK_EQ(mOperationTypes.count(OperationType::OEM_OPERATION), size_t(0)); + CHECK_EQ(mOperationTypes.count(V1_3::OperationType::OEM_OPERATION), size_t(0)); if (operationMask) { - std::for_each(mOperationTypes.begin(), mOperationTypes.end(), [](OperationType type) { - CHECK_EQ(operationToFirstEncoding.count(type), size_t(0)); - }); + std::for_each(mOperationTypes.begin(), mOperationTypes.end(), + [](V1_3::OperationType type) { + CHECK_EQ(operationToFirstEncoding.count(type), size_t(0)); + }); } } ~PartitioningDriver() override {} - Return<void> getVersionString(getVersionString_cb cb) override { + hardware::Return<void> getVersionString(getVersionString_cb cb) override { cb(V1_0::ErrorStatus::NONE, mVersionString); - return Void(); + return hardware::Void(); } - Return<V1_3::ErrorStatus> prepareModel_1_3( - const Model& model, ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache, - const hidl_vec<hidl_handle>& dataCache, const CacheToken& token, + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, const sp<V1_3::IPreparedModelCallback>& callback) override { if (mOEM == OEMIndecisive) { for (const auto& operation : model.main.operations) { - if (operation.type == OperationType::OEM_OPERATION) { + if (operation.type == V1_3::OperationType::OEM_OPERATION) { callback->notify_1_3(V1_3::ErrorStatus::INVALID_ARGUMENT, nullptr); return V1_3::ErrorStatus::INVALID_ARGUMENT; } @@ -354,7 +367,7 @@ class PartitioningDriver : public SampleDriver { V1_3::ErrorStatus outStatus = V1_3::ErrorStatus::INVALID_ARGUMENT; auto ret = getSupportedOperations_1_3( model, [&outStatus](V1_3::ErrorStatus inStatus, - const hidl_vec<bool>& supportedOperations) { + const hardware::hidl_vec<bool>& supportedOperations) { if (inStatus == V1_3::ErrorStatus::NONE) { if (std::all_of(supportedOperations.begin(), supportedOperations.end(), [](bool v) { return v; })) { @@ -371,57 +384,60 @@ class PartitioningDriver : public SampleDriver { } } - Return<DeviceStatus> getStatus() override { return DeviceStatus::AVAILABLE; } + hardware::Return<V1_0::DeviceStatus> getStatus() override { + return V1_0::DeviceStatus::AVAILABLE; + } - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { cb(V1_3::ErrorStatus::NONE, mCapabilities); - return Void(); + return hardware::Void(); } - Return<void> getSupportedOperations_1_3(const Model& model, - getSupportedOperations_1_3_cb cb) override { + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model& model, + getSupportedOperations_1_3_cb cb) override { if (!android::nn::validateModel(model)) { cb(V1_3::ErrorStatus::INVALID_ARGUMENT, std::vector<bool>()); - return Void(); + return hardware::Void(); } cb(V1_3::ErrorStatus::NONE, getSupportedOperationsForSubgraph(model, model.main)); - return Void(); + return hardware::Void(); } - Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) override { + hardware::Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) override { cb(V1_0::ErrorStatus::NONE, /*numModelCache=*/1, /*numDataCache=*/1); - return Void(); + return hardware::Void(); } private: - std::vector<bool> getSupportedOperationsForSubgraph(const Model& model, - const Subgraph& subgraph) { + std::vector<bool> getSupportedOperationsForSubgraph(const V1_3::Model& model, + const V1_3::Subgraph& subgraph) { CHECK(&subgraph == &model.main || std::find_if(model.referenced.begin(), model.referenced.end(), - [&subgraph](const Subgraph& refSubgraph) { + [&subgraph](const V1_3::Subgraph& refSubgraph) { return &subgraph == &refSubgraph; }) != model.referenced.end()); auto supportsEntireSubgraph = [this, &model, &subgraph](uint32_t refSubgraphOperandIndex) { CHECK_LT(refSubgraphOperandIndex, subgraph.operands.size()); - const Operand& refSubgraphOperand = subgraph.operands[refSubgraphOperandIndex]; - CHECK(refSubgraphOperand.lifetime == OperandLifeTime::SUBGRAPH); + const V1_3::Operand& refSubgraphOperand = subgraph.operands[refSubgraphOperandIndex]; + CHECK(refSubgraphOperand.lifetime == V1_3::OperandLifeTime::SUBGRAPH); CHECK_LT(refSubgraphOperand.location.offset, model.referenced.size()); - const Subgraph& refSubgraph = model.referenced[refSubgraphOperand.location.offset]; + const V1_3::Subgraph& refSubgraph = + model.referenced[refSubgraphOperand.location.offset]; std::vector<bool> supported = getSupportedOperationsForSubgraph(model, refSubgraph); return std::all_of(supported.begin(), supported.end(), [](bool x) { return x; }); }; const size_t count = subgraph.operations.size(); std::vector<bool> supported(count); for (size_t i = 0; i < count; i++) { - const Operation& operation = subgraph.operations[i]; + const V1_3::Operation& operation = subgraph.operations[i]; if (mOperationTypes.count(operation.type)) { - if (operation.type == OperationType::IF) { + if (operation.type == V1_3::OperationType::IF) { namespace op = android::nn::operation_if; CHECK_GE(operation.inputs.size(), op::kFirstInput); supported[i] = supportsEntireSubgraph(operation.inputs[op::kThenModelOperand]) && supportsEntireSubgraph(operation.inputs[op::kElseModelOperand]); - } else if (operation.type == OperationType::WHILE) { + } else if (operation.type == V1_3::OperationType::WHILE) { namespace op = android::nn::operation_while; CHECK_GE(operation.inputs.size(), op::kFirstInput); supported[i] = @@ -432,7 +448,7 @@ class PartitioningDriver : public SampleDriver { } continue; } - if (operation.type == OperationType::OEM_OPERATION) { + if (operation.type == V1_3::OperationType::OEM_OPERATION) { supported[i] = (mOEM != OEMNo); continue; } @@ -447,72 +463,75 @@ class PartitioningDriver : public SampleDriver { } std::string mVersionString; - Capabilities mCapabilities; + V1_3::Capabilities mCapabilities; uint32_t mOperationMask; OEM mOEM; - std::set<OperationType> mOperationTypes; + std::set<V1_3::OperationType> mOperationTypes; }; // Like PartitioningDriver, but implementing 1.2 class PartitioningDriverV1_2 : public V1_2::IDevice { public: - PartitioningDriverV1_2(const char* name, const char* version, Capabilities capabilities, + PartitioningDriverV1_2(const char* name, const char* version, V1_3::Capabilities capabilities, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : mLatestDriver(new PartitioningDriver(name, version, capabilities, operationMask, oem, operationTypes)) {} - Return<void> getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_2(_hidl_cb); } - Return<void> getSupportedOperations_1_2(const V1_2::Model& model, - getSupportedOperations_1_2_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_2( + const V1_2::Model& model, getSupportedOperations_1_2_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_2(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference preference, - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, const sp<V1_2::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_2(model, preference, modelCache, dataCache, token, actualCallback); } - Return<void> getVersionString(getVersionString_cb _hidl_cb) override { + hardware::Return<void> getVersionString(getVersionString_cb _hidl_cb) override { return mLatestDriver->getVersionString(_hidl_cb); } - Return<void> getType(getType_cb _hidl_cb) override { return mLatestDriver->getType(_hidl_cb); } - Return<void> getSupportedExtensions(getSupportedExtensions_cb _hidl_cb) { + hardware::Return<void> getType(getType_cb _hidl_cb) override { + return mLatestDriver->getType(_hidl_cb); + } + hardware::Return<void> getSupportedExtensions(getSupportedExtensions_cb _hidl_cb) { return mLatestDriver->getSupportedExtensions(_hidl_cb); } - Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb _hidl_cb) { + hardware::Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb _hidl_cb) { return mLatestDriver->getNumberOfCacheFilesNeeded(_hidl_cb); } - Return<V1_0::ErrorStatus> prepareModelFromCache( - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) { + hardware::Return<V1_0::ErrorStatus> prepareModelFromCache( + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_2::IPreparedModelCallback>& callback) { return mLatestDriver->prepareModelFromCache(modelCache, dataCache, token, callback); } - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_1(_hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_1(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_1(model, preference, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); @@ -525,33 +544,33 @@ class PartitioningDriverV1_2 : public V1_2::IDevice { // Like PartitioningDriver, but implementing 1.1 class PartitioningDriverV1_1 : public V1_1::IDevice { public: - PartitioningDriverV1_1(const char* name, const char* version, Capabilities capabilities, + PartitioningDriverV1_1(const char* name, const char* version, V1_3::Capabilities capabilities, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : mLatestDriver(new PartitioningDriver(name, version, capabilities, operationMask, oem, operationTypes)) {} - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_1(_hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_1(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_1(model, preference, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); @@ -564,25 +583,25 @@ class PartitioningDriverV1_1 : public V1_1::IDevice { // Like PartitioningDriver, but implementing 1.0 class PartitioningDriverV1_0 : public V1_0::IDevice { public: - PartitioningDriverV1_0(const char* name, const char* version, Capabilities capabilities, + PartitioningDriverV1_0(const char* name, const char* version, V1_3::Capabilities capabilities, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : mLatestDriver(new PartitioningDriver(name, version, capabilities, operationMask, oem, operationTypes)) {} - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } private: const sp<V1_3::IDevice> mLatestDriver; @@ -949,7 +968,7 @@ class PartitioningTest : public ::testing::Test { // From a vector of DeviceSpecification, create a vector of // Devices. struct DeviceSpecification { - DeviceSpecification(const std::string& name, const Capabilities& capabilities, + DeviceSpecification(const std::string& name, const V1_3::Capabilities& capabilities, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo) : mName(name), @@ -959,30 +978,31 @@ class PartitioningTest : public ::testing::Test { mOEM(oem) {} DeviceSpecification(const std::string& name, float perf, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : DeviceSpecification(name, perf, perf, operationMask, oem, operationTypes) {} DeviceSpecification(const std::string& name, float perf, float perfRelaxed, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : DeviceSpecification(name, kVersionString, perf, perfRelaxed, operationMask, oem, operationTypes) {} DeviceSpecification(const std::string& name, const std::string& version, float perf, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : DeviceSpecification(name, version, perf, perf, operationMask, oem, operationTypes) {} DeviceSpecification(const std::string& name, const std::string& version, float perf, float perfRelaxed, uint32_t operationMask, PartitioningDriver::OEM oem = PartitioningDriver::OEMNo, - std::set<OperationType> operationTypes = {}) + std::set<V1_3::OperationType> operationTypes = {}) : mName(name), mVersionString(version), mOperationMask(operationMask), mOEM(oem), mOperationTypes(std::move(operationTypes)) { - PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; - PerformanceInfo perfRelaxedInfo = {.execTime = perfRelaxed, .powerUsage = perfRelaxed}; + V1_0::PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf}; + V1_0::PerformanceInfo perfRelaxedInfo = {.execTime = perfRelaxed, + .powerUsage = perfRelaxed}; mCapabilities = { .relaxedFloat32toFloat16PerformanceScalar = perfRelaxedInfo, .relaxedFloat32toFloat16PerformanceTensor = perfRelaxedInfo, @@ -1004,11 +1024,11 @@ class PartitioningTest : public ::testing::Test { std::string mName; std::string mVersionString; - Capabilities mCapabilities; + V1_3::Capabilities mCapabilities; HalVersion mHalVersion = HalVersion::LATEST; uint32_t mOperationMask; PartitioningDriver::OEM mOEM = PartitioningDriver::OEMNo; - std::set<OperationType> mOperationTypes; + std::set<V1_3::OperationType> mOperationTypes; static constexpr char kVersionString[] = "JUST_AN_EXAMPLE"; @@ -1137,7 +1157,7 @@ class PartitioningTest : public ::testing::Test { // actual definitions ASSERT_LT(model->operationCount(), kPseudoDefiningOperationBase); for (uint32_t i = 0, e = model->operationCount(); i < e; i++) { - const Operation& operation = model->getOperation(i); + const V1_3::Operation& operation = android::nn::convertToV1_3(model->getOperation(i)); for (uint32_t output : operation.outputs) { (*defMap)[output] = i; } @@ -1149,12 +1169,12 @@ class PartitioningTest : public ::testing::Test { } // look for NO_VALUE and CONSTANT_COPY for (uint32_t i = 0, e = model->operandCount(); i < e; i++) { - const Operand& operand = model->getOperand(i); + const V1_3::Operand& operand = android::nn::convertToV1_3(model->getOperand(i)); switch (operand.lifetime) { - case OperandLifeTime::NO_VALUE: + case V1_3::OperandLifeTime::NO_VALUE: (*defMap)[i] = kPseudoDefiningOperationNoValue; break; - case OperandLifeTime::CONSTANT_COPY: { + case V1_3::OperandLifeTime::CONSTANT_COPY: { ASSERT_EQ(operand.location.length, sizeof(uint32_t)); uint32_t value; memcpy(&value, model->getPointerToOperandValue(operand.location.offset), @@ -1163,9 +1183,9 @@ class PartitioningTest : public ::testing::Test { (*defMap)[i] = kPseudoDefiningOperationConstantCopy0 + value; break; } - case OperandLifeTime::TEMPORARY_VARIABLE: - case OperandLifeTime::SUBGRAPH_INPUT: - case OperandLifeTime::SUBGRAPH_OUTPUT: + case V1_3::OperandLifeTime::TEMPORARY_VARIABLE: + case V1_3::OperandLifeTime::SUBGRAPH_INPUT: + case V1_3::OperandLifeTime::SUBGRAPH_OUTPUT: // already handled break; default: @@ -1207,7 +1227,6 @@ class PartitioningTest : public ::testing::Test { bool compare(const Operand& operandA, const Operand& operandB) { if (operandA.type != operandB.type || operandA.dimensions != operandB.dimensions || - operandA.numberOfConsumers != operandB.numberOfConsumers || operandA.scale != operandB.scale || operandA.zeroPoint != operandB.zeroPoint) { return false; } @@ -2021,8 +2040,8 @@ TEST_F(PartitioningTest, Perf) { // WrapperOperandType is the NeuralNetworksWrapper.h representation of a // full operand type (WrapperType plus dimensions plus other attributes). - auto TestType = [](OperandType operandType) { - if (operandType == OperandType::SUBGRAPH) { + auto TestType = [](V1_3::OperandType operandType) { + if (operandType == V1_3::OperandType::SUBGRAPH) { // SUBGRAPH capabilities are handled differently. return; } @@ -2037,11 +2056,11 @@ TEST_F(PartitioningTest, Perf) { model.finish(); ASSERT_TRUE(model.isValid()); - const Capabilities baseCapabilities = makeCapabilities(0.5); + const V1_3::Capabilities baseCapabilities = makeCapabilities(0.5); { // better than base - Capabilities goodCapabilities = baseCapabilities; + V1_3::Capabilities goodCapabilities = baseCapabilities; update(&goodCapabilities, operandType, 0.25); const auto devices = @@ -2062,7 +2081,7 @@ TEST_F(PartitioningTest, Perf) { { // worse than base - Capabilities badCapabilities = baseCapabilities; + V1_3::Capabilities badCapabilities = baseCapabilities; update(&badCapabilities, operandType, 0.75); const auto devices = makeDevices({{"base", baseCapabilities, ~0U, PartitioningDriver::OEMYes}, @@ -2081,13 +2100,13 @@ TEST_F(PartitioningTest, Perf) { } }; - for (uint32_t type = static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MIN); - type <= static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MAX); ++type) { - TestType(static_cast<OperandType>(type)); + for (uint32_t type = static_cast<uint32_t>(V1_3::OperandTypeRange::FUNDAMENTAL_MIN); + type <= static_cast<uint32_t>(V1_3::OperandTypeRange::FUNDAMENTAL_MAX); ++type) { + TestType(static_cast<V1_3::OperandType>(type)); } - for (uint32_t type = static_cast<uint32_t>(OperandTypeRange::OEM_MIN); - type <= static_cast<uint32_t>(OperandTypeRange::OEM_MAX); ++type) { - TestType(static_cast<OperandType>(type)); + for (uint32_t type = static_cast<uint32_t>(V1_3::OperandTypeRange::OEM_MIN); + type <= static_cast<uint32_t>(V1_3::OperandTypeRange::OEM_MAX); ++type) { + TestType(static_cast<V1_3::OperandType>(type)); } } @@ -2167,8 +2186,9 @@ void DynamicTemporariesTest::compileModelAndComparePlan() { ASSERT_TRUE(mModel.has_value()); ASSERT_TRUE(!mCompilation.has_value()); - auto devices = makeDevices({{"fill", 0.9, 0U, PartitioningDriver::OEMNo, {OperationType::FILL}}, - {"add", 0.9, 0U, PartitioningDriver::OEMNo, {OperationType::ADD}}}); + auto devices = + makeDevices({{"fill", 0.9, 0U, PartitioningDriver::OEMNo, {V1_3::OperationType::FILL}}, + {"add", 0.9, 0U, PartitioningDriver::OEMNo, {V1_3::OperationType::ADD}}}); mCompilation = PartitioningCompilation(&mModel.value(), devices); ASSERT_EQ(mCompilation->setPartitioning(DeviceManager::kPartitioningWithoutFallback), @@ -2824,44 +2844,44 @@ class PerfTest : public ::testing::Test {}; TEST_F(PerfTest, Lookup) { // Derive an arbitrary (but reproducible) performance value from an OperandType. // We'll use this to ensure that we can save and then recover a type's performance. - auto typePerf = [](OperandType type) { return float(static_cast<uint32_t>(type)); }; + auto typePerf = [](V1_3::OperandType type) { return float(static_cast<uint32_t>(type)); }; - Capabilities capabilities = makeCapabilities(-1.0f); + V1_3::Capabilities capabilities = makeCapabilities(-1.0f); - for (uint32_t type = static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MIN); - type <= static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MAX); ++type) { - OperandType operandType = static_cast<OperandType>(type); + for (uint32_t type = static_cast<uint32_t>(V1_3::OperandTypeRange::FUNDAMENTAL_MIN); + type <= static_cast<uint32_t>(V1_3::OperandTypeRange::FUNDAMENTAL_MAX); ++type) { + V1_3::OperandType operandType = static_cast<V1_3::OperandType>(type); update(&capabilities, operandType, typePerf(operandType)); } - for (uint32_t type = static_cast<uint32_t>(OperandTypeRange::OEM_MIN); - type <= static_cast<uint32_t>(OperandTypeRange::OEM_MAX); ++type) { - OperandType operandType = static_cast<OperandType>(type); + for (uint32_t type = static_cast<uint32_t>(V1_3::OperandTypeRange::OEM_MIN); + type <= static_cast<uint32_t>(V1_3::OperandTypeRange::OEM_MAX); ++type) { + V1_3::OperandType operandType = static_cast<V1_3::OperandType>(type); update(&capabilities, operandType, typePerf(operandType)); } // Make sure lookup retrieves the values stored by update - for (uint32_t type = static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MIN); - type <= static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MAX); ++type) { - OperandType operandType = static_cast<OperandType>(type); - if (operandType == OperandType::SUBGRAPH) { + for (uint32_t type = static_cast<uint32_t>(V1_3::OperandTypeRange::FUNDAMENTAL_MIN); + type <= static_cast<uint32_t>(V1_3::OperandTypeRange::FUNDAMENTAL_MAX); ++type) { + V1_3::OperandType operandType = static_cast<V1_3::OperandType>(type); + if (operandType == V1_3::OperandType::SUBGRAPH) { // SUBGRAPH capabilities are handled differently. continue; } SCOPED_TRACE(toString(operandType)); EXPECT_EQ(lookupExecTime(capabilities, operandType), typePerf(operandType)); } - for (uint32_t type = static_cast<uint32_t>(OperandTypeRange::OEM_MIN); - type <= static_cast<uint32_t>(OperandTypeRange::OEM_MAX); ++type) { - OperandType operandType = static_cast<OperandType>(type); + for (uint32_t type = static_cast<uint32_t>(V1_3::OperandTypeRange::OEM_MIN); + type <= static_cast<uint32_t>(V1_3::OperandTypeRange::OEM_MAX); ++type) { + V1_3::OperandType operandType = static_cast<V1_3::OperandType>(type); SCOPED_TRACE(toString(operandType)); EXPECT_EQ(lookupExecTime(capabilities, operandType), typePerf(operandType)); } // Check the behavior of a missing type - OperandType operandType = - static_cast<OperandType>(static_cast<uint32_t>(OperandTypeRange::BASE_MAX) + 1); + V1_3::OperandType operandType = static_cast<V1_3::OperandType>( + static_cast<uint32_t>(V1_3::OperandTypeRange::BASE_MAX) + 1); EXPECT_EQ(lookupExecTime(capabilities, operandType), FLT_MAX); } @@ -3005,7 +3025,7 @@ TEST_F(ControlFlowPartitioningTest, IF_SimplePlan) { // The device supports all operations. const auto devices = - makeDevices({{"ALL", 0.9, ~0U, PartitioningDriver::OEMNo, {OperationType::IF}}}); + makeDevices({{"ALL", 0.9, ~0U, PartitioningDriver::OEMNo, {V1_3::OperationType::IF}}}); ExecutionPlan plan; ASSERT_EQ(models[0]->partitionTheWork(devices, ExecutePreference::PREFER_LOW_POWER, @@ -3023,7 +3043,7 @@ TEST_F(ControlFlowPartitioningTest, WHILE_SimplePlan) { 0.9, ~0U, PartitioningDriver::OEMNo, - {OperationType::WHILE, OperationType::EQUAL}}}); + {V1_3::OperationType::WHILE, V1_3::OperationType::EQUAL}}}); ExecutionPlan plan; ASSERT_EQ(models[0]->partitionTheWork(devices, ExecutePreference::PREFER_LOW_POWER, @@ -3047,7 +3067,7 @@ void ControlFlowPartitioningTest::testIfUnknownSize(Dimensioned dimensionedMain, // The device supports all operations but the partitioner ignores its IF // support due to http://b/159076604#comment5. const auto devices = - makeDevices({{"ALL", 0.9, ~0U, PartitioningDriver::OEMNo, {OperationType::IF}}}); + makeDevices({{"ALL", 0.9, ~0U, PartitioningDriver::OEMNo, {V1_3::OperationType::IF}}}); ExecutionPlan plan; ASSERT_EQ(models[0]->partitionTheWork(devices, ExecutePreference::PREFER_LOW_POWER, @@ -3090,7 +3110,7 @@ void ControlFlowPartitioningTest::testWhileUnknownSize(Dimensioned dimensionedMa 0.9, ~0U, PartitioningDriver::OEMNo, - {OperationType::WHILE, OperationType::EQUAL}}}); + {V1_3::OperationType::WHILE, V1_3::OperationType::EQUAL}}}); ExecutionPlan plan; ASSERT_EQ(models[0]->partitionTheWork(devices, ExecutePreference::PREFER_LOW_POWER, diff --git a/nn/runtime/test/TestPartitioningRandom.cpp b/nn/runtime/test/TestPartitioningRandom.cpp index 51d7910cc..294d93ad5 100644 --- a/nn/runtime/test/TestPartitioningRandom.cpp +++ b/nn/runtime/test/TestPartitioningRandom.cpp @@ -95,11 +95,15 @@ namespace android { -using namespace nn::hal; +namespace V1_0 = ::android::hardware::neuralnetworks::V1_0; +namespace V1_1 = ::android::hardware::neuralnetworks::V1_1; +namespace V1_2 = ::android::hardware::neuralnetworks::V1_2; +namespace V1_3 = ::android::hardware::neuralnetworks::V1_3; using CompilationBuilder = nn::CompilationBuilder; -using Device = nn::Device; using DeviceManager = nn::DeviceManager; +using Device = nn::Device; using ExecutionPlan = nn::ExecutionPlan; +using HalCacheToken = nn::HalCacheToken; using HalVersion = nn::HalVersion; using HidlModel = V1_3::Model; using ModelBuilder = nn::ModelBuilder; @@ -335,7 +339,7 @@ class RandomPartitioningTest : public ::testing::TestWithParam<unsigned> { public: RandomPartitioningTest() : mRandNumEng(GetParam() /* seed */), mRandNumUnitDist(0.0, 1.0) {} - static Signature getSignature(const HidlModel& model, const Operation& operation); + static Signature getSignature(const HidlModel& model, const V1_3::Operation& operation); protected: static V1_0::IDevice* makeTestDriver(HalVersion version, const char* name, @@ -500,7 +504,8 @@ HalVersion RandomPartitioningTest::getMinHalVersion(ANeuralNetworksOperationType return kOperationToVersion.at(type); } -Signature RandomPartitioningTest::getSignature(const HidlModel& model, const Operation& operation) { +Signature RandomPartitioningTest::getSignature(const HidlModel& model, + const V1_3::Operation& operation) { static const auto kOperationToActivation = [] { std::map<ANeuralNetworksOperationType, int> result; for (const auto& pattern : kOperationPatterns) { @@ -516,9 +521,10 @@ Signature RandomPartitioningTest::getSignature(const HidlModel& model, const Ope return Signature(operationType, -1); } - const Operand& operand = model.main.operands[operation.inputs[activationFunctionInputIndex]]; - CHECK(operand.lifetime == OperandLifeTime::CONSTANT_COPY); - CHECK(operand.type == OperandType::INT32); + const V1_3::Operand& operand = + model.main.operands[operation.inputs[activationFunctionInputIndex]]; + CHECK(operand.lifetime == V1_3::OperandLifeTime::CONSTANT_COPY); + CHECK(operand.type == V1_3::OperandType::INT32); int32_t value; memcpy(&value, &model.operandValues[operand.location.offset], operand.location.length); return Signature(operationType, value); @@ -546,21 +552,21 @@ class TestDriver : public SampleDriver { TestDriver(const char* name, std::set<Signature> signatures) : SampleDriver(name), mSignatures(std::move(signatures)) {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb _hidl_cb) override { android::nn::initVLogMask(); - const PerformanceInfo kPerf = {.execTime = 0.75f, .powerUsage = 0.75f}; - Capabilities capabilities = { + const V1_0::PerformanceInfo kPerf = {.execTime = 0.75f, .powerUsage = 0.75f}; + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = kPerf, .relaxedFloat32toFloat16PerformanceTensor = kPerf, .operandPerformance = nn::nonExtensionOperandPerformance<HalVersion::V1_3>(kPerf), .ifPerformance = kPerf, .whilePerformance = kPerf}; _hidl_cb(V1_3::ErrorStatus::NONE, capabilities); - return Void(); + return hardware::Void(); } - Return<void> getSupportedOperations_1_3(const HidlModel& model, - getSupportedOperations_1_3_cb cb) override { + hardware::Return<void> getSupportedOperations_1_3(const HidlModel& model, + getSupportedOperations_1_3_cb cb) override { if (nn::validateModel(model)) { const size_t count = model.main.operations.size(); std::vector<bool> supported(count); @@ -572,19 +578,20 @@ class TestDriver : public SampleDriver { } else { cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}); } - return Void(); + return hardware::Void(); } - Return<V1_3::ErrorStatus> prepareModel_1_3( - const HidlModel& model, ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache, - const hidl_vec<hidl_handle>& dataCache, const CacheToken& token, + hardware::Return<V1_3::ErrorStatus> prepareModel_1_3( + const HidlModel& model, V1_1::ExecutionPreference preference, V1_3::Priority priority, + const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, const sp<V1_3::IPreparedModelCallback>& callback) override { // NOTE: We verify that all operations in the model are supported. V1_3::ErrorStatus outStatus = V1_3::ErrorStatus::INVALID_ARGUMENT; auto ret = getSupportedOperations_1_3( model, [&outStatus](V1_3::ErrorStatus inStatus, - const hidl_vec<bool>& supportedOperations) { + const hardware::hidl_vec<bool>& supportedOperations) { if (inStatus == V1_3::ErrorStatus::NONE) { if (std::all_of(supportedOperations.begin(), supportedOperations.end(), [](bool v) { return v; })) { @@ -610,57 +617,60 @@ class TestDriverV1_2 : public V1_2::IDevice { public: TestDriverV1_2(const char* name, std::set<Signature> signatures) : mLatestDriver(new TestDriver(name, std::move(signatures))) {} - Return<void> getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_2(_hidl_cb); } - Return<void> getSupportedOperations_1_2(const V1_2::Model& model, - getSupportedOperations_1_2_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_2( + const V1_2::Model& model, getSupportedOperations_1_2_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_2(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_2( - const V1_2::Model& model, ExecutionPreference preference, - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_2( + const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, const sp<V1_2::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_2(model, preference, modelCache, dataCache, token, actualCallback); } - Return<void> getVersionString(getVersionString_cb _hidl_cb) override { + hardware::Return<void> getVersionString(getVersionString_cb _hidl_cb) override { return mLatestDriver->getVersionString(_hidl_cb); } - Return<void> getType(getType_cb _hidl_cb) override { return mLatestDriver->getType(_hidl_cb); } - Return<void> getSupportedExtensions(getSupportedExtensions_cb _hidl_cb) { + hardware::Return<void> getType(getType_cb _hidl_cb) override { + return mLatestDriver->getType(_hidl_cb); + } + hardware::Return<void> getSupportedExtensions(getSupportedExtensions_cb _hidl_cb) { return mLatestDriver->getSupportedExtensions(_hidl_cb); } - Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb _hidl_cb) { + hardware::Return<void> getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb _hidl_cb) { return mLatestDriver->getNumberOfCacheFilesNeeded(_hidl_cb); } - Return<V1_0::ErrorStatus> prepareModelFromCache( - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) { + hardware::Return<V1_0::ErrorStatus> prepareModelFromCache( + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, const HalCacheToken& token, + const sp<V1_2::IPreparedModelCallback>& callback) { return mLatestDriver->prepareModelFromCache(modelCache, dataCache, token, callback); } - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_1(_hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_1(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_1(model, preference, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); @@ -675,27 +685,27 @@ class TestDriverV1_1 : public V1_1::IDevice { public: TestDriverV1_1(const char* name, std::set<Signature> signatures) : mLatestDriver(new TestDriver(name, std::move(signatures))) {} - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mLatestDriver->getCapabilities_1_1(_hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations_1_1(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel_1_1(model, preference, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); @@ -710,19 +720,19 @@ class TestDriverV1_0 : public V1_0::IDevice { public: TestDriverV1_0(const char* name, std::set<Signature> signatures) : mLatestDriver(new TestDriver(name, std::move(signatures))) {} - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mLatestDriver->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mLatestDriver->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mLatestDriver->prepareModel(model, actualCallback); } - Return<DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mLatestDriver->getStatus(); } private: const sp<V1_3::IDevice> mLatestDriver; diff --git a/nn/runtime/test/TestRemoveDefaultArguments.cpp b/nn/runtime/test/TestRemoveDefaultArguments.cpp index 8726adc85..daef6bf60 100644 --- a/nn/runtime/test/TestRemoveDefaultArguments.cpp +++ b/nn/runtime/test/TestRemoveDefaultArguments.cpp @@ -98,7 +98,6 @@ const test_helper::TestModel& get_test_model_align_corners_2x2_to_1x1(); namespace android::nn { namespace { -using namespace hal; using sample_driver::SampleDriverPartial; using Result = test_wrapper::Result; using WrapperOperandType = test_wrapper::OperandType; @@ -113,18 +112,18 @@ class TestDriver : public SampleDriverPartial { public: TestDriver() : SampleDriverPartial(kTestDriverName) {} - Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override { cb(V1_3::ErrorStatus::NONE, {/* Placeholder zero-filled capabilities. */}); - return Void(); + return hardware::Void(); } void setSupportedInputCount(uint32_t count) { mSupportedInputCount = count; } private: - std::vector<bool> getSupportedOperationsImpl(const Model& model) const override { + std::vector<bool> getSupportedOperationsImpl(const V1_3::Model& model) const override { std::vector<bool> supported(model.main.operations.size()); std::transform(model.main.operations.begin(), model.main.operations.end(), - supported.begin(), [this](const Operation& operation) { + supported.begin(), [this](const V1_3::Operation& operation) { SCOPED_TRACE("operation = " + toString(operation.type)); EXPECT_EQ(operation.inputs.size(), mSupportedInputCount); return operation.inputs.size() == mSupportedInputCount; diff --git a/nn/runtime/test/TestUnspecifiedDimensions.cpp b/nn/runtime/test/TestUnspecifiedDimensions.cpp index c1bad04a8..5a2287c78 100644 --- a/nn/runtime/test/TestUnspecifiedDimensions.cpp +++ b/nn/runtime/test/TestUnspecifiedDimensions.cpp @@ -17,7 +17,10 @@ #include "TestNeuralNetworksWrapper.h" #include <sys/mman.h> +#include <memory> +#include <string> #include <tuple> +#include <utility> #include <vector> #include <android-base/macros.h> diff --git a/nn/runtime/test/TestVersionedInterfaces.cpp b/nn/runtime/test/TestVersionedInterfaces.cpp index 6d1306d57..b4f32bcde 100644 --- a/nn/runtime/test/TestVersionedInterfaces.cpp +++ b/nn/runtime/test/TestVersionedInterfaces.cpp @@ -22,6 +22,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <hidl/Status.h> +#include <nnapi/TypeUtils.h> #include <utils/Errors.h> #include <limits> @@ -37,7 +38,6 @@ namespace android::nn { namespace { -using namespace hal; using testing::_; using testing::Invoke; using testing::InvokeWithoutArgs; @@ -45,40 +45,59 @@ using testing::MockFunction; using MockDeviceFactory = MockFunction<sp<V1_0::IDevice>(bool blocking)>; constexpr uint32_t kNoCacheFilesNeeded = 0; -constexpr uint32_t kMaxNumberOfCacheFiles = - static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES); -constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(), - .timeInDriver = std::numeric_limits<uint64_t>::max()}; +constexpr V1_2::Timing kNoTiming12 = {.timeOnDevice = std::numeric_limits<uint64_t>::max(), + .timeInDriver = std::numeric_limits<uint64_t>::max()}; +constexpr V1_0::PerformanceInfo kNoPerformanceInfo = {.execTime = FLT_MAX, .powerUsage = FLT_MAX}; +constexpr Timing kNoTiming = {}; template <typename... Args> auto makeCallbackReturn(Args&&... args) { return [argPack = std::make_tuple(std::forward<Args>(args)...)](const auto& cb) { std::apply(cb, argPack); - return Void(); + return hardware::Void(); }; }; -class MockDevice : public IDevice { +class MockDevice : public V1_3::IDevice { public: static sp<MockDevice> create() { const sp<MockDevice> mockDevice = new MockDevice(); - const auto linkToDeathRet_ret = []() -> Return<bool> { return true; }; - const auto getCapabilities_ret = - makeCallbackReturn(V1_0::ErrorStatus::NONE, V1_0::Capabilities{}); + const auto linkToDeathRet_ret = []() -> hardware::Return<bool> { return true; }; + const auto getCapabilities_ret = makeCallbackReturn( + V1_0::ErrorStatus::NONE, V1_0::Capabilities{ + .float32Performance = kNoPerformanceInfo, + .quantized8Performance = kNoPerformanceInfo, + }); const auto getCapabilities_1_1_ret = - makeCallbackReturn(V1_0::ErrorStatus::NONE, V1_1::Capabilities{}); + makeCallbackReturn(V1_0::ErrorStatus::NONE, + V1_1::Capabilities{ + .float32Performance = kNoPerformanceInfo, + .quantized8Performance = kNoPerformanceInfo, + .relaxedFloat32toFloat16Performance = kNoPerformanceInfo, + }); const auto getVersionString_ret = makeCallbackReturn(V1_0::ErrorStatus::NONE, "Google-MockV1"); - const auto getType_ret = makeCallbackReturn(V1_0::ErrorStatus::NONE, DeviceType::OTHER); - const auto getCapabilities_1_2_ret = - makeCallbackReturn(V1_0::ErrorStatus::NONE, V1_2::Capabilities{}); + const auto getType_ret = + makeCallbackReturn(V1_0::ErrorStatus::NONE, V1_2::DeviceType::OTHER); + const auto getCapabilities_1_2_ret = makeCallbackReturn( + V1_0::ErrorStatus::NONE, + V1_2::Capabilities{ + .relaxedFloat32toFloat16PerformanceScalar = kNoPerformanceInfo, + .relaxedFloat32toFloat16PerformanceTensor = kNoPerformanceInfo, + }); const auto getSupportedExtensions_ret = - makeCallbackReturn(V1_0::ErrorStatus::NONE, hidl_vec<Extension>{}); + makeCallbackReturn(V1_0::ErrorStatus::NONE, hardware::hidl_vec<V1_2::Extension>{}); const auto getNumberOfCacheFilesNeeded_ret = makeCallbackReturn( V1_0::ErrorStatus::NONE, kMaxNumberOfCacheFiles, kMaxNumberOfCacheFiles); - const auto getCapabilities_1_3_ret = - makeCallbackReturn(V1_3::ErrorStatus::NONE, V1_3::Capabilities{}); + const auto getCapabilities_1_3_ret = makeCallbackReturn( + V1_3::ErrorStatus::NONE, + V1_3::Capabilities{ + .relaxedFloat32toFloat16PerformanceScalar = kNoPerformanceInfo, + .relaxedFloat32toFloat16PerformanceTensor = kNoPerformanceInfo, + .ifPerformance = kNoPerformanceInfo, + .whilePerformance = kNoPerformanceInfo, + }); ON_CALL(*mockDevice, linkToDeathRet()).WillByDefault(Invoke(linkToDeathRet_ret)); ON_CALL(*mockDevice, getCapabilities(_)).WillByDefault(Invoke(getCapabilities_ret)); @@ -108,73 +127,82 @@ class MockDevice : public IDevice { } // IBase methods below. - Return<bool> linkToDeath(const sp<hidl_death_recipient>& recipient, - uint64_t /*cookie*/) override { + hardware::Return<bool> linkToDeath(const sp<hardware::hidl_death_recipient>& recipient, + uint64_t /*cookie*/) override { mDeathRecipient = recipient; return linkToDeathRet(); } - MOCK_METHOD(Return<void>, ping, (), (override)); + MOCK_METHOD(hardware::Return<void>, ping, (), (override)); // V1_0 methods below. - MOCK_METHOD(Return<void>, getCapabilities, (getCapabilities_cb cb), (override)); - MOCK_METHOD(Return<void>, getSupportedOperations, + MOCK_METHOD(hardware::Return<void>, getCapabilities, (getCapabilities_cb cb), (override)); + MOCK_METHOD(hardware::Return<void>, getSupportedOperations, (const V1_0::Model& model, getSupportedOperations_cb cb), (override)); - MOCK_METHOD(Return<V1_0::ErrorStatus>, prepareModel, + MOCK_METHOD(hardware::Return<V1_0::ErrorStatus>, prepareModel, (const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback), (override)); - MOCK_METHOD(Return<DeviceStatus>, getStatus, (), (override)); + MOCK_METHOD(hardware::Return<V1_0::DeviceStatus>, getStatus, (), (override)); // V1_1 methods below. - MOCK_METHOD(Return<void>, getCapabilities_1_1, (getCapabilities_1_1_cb cb), (override)); - MOCK_METHOD(Return<void>, getSupportedOperations_1_1, + MOCK_METHOD(hardware::Return<void>, getCapabilities_1_1, (getCapabilities_1_1_cb cb), + (override)); + MOCK_METHOD(hardware::Return<void>, getSupportedOperations_1_1, (const V1_1::Model& model, getSupportedOperations_1_1_cb cb), (override)); - MOCK_METHOD(Return<V1_0::ErrorStatus>, prepareModel_1_1, - (const V1_1::Model& model, ExecutionPreference preference, + MOCK_METHOD(hardware::Return<V1_0::ErrorStatus>, prepareModel_1_1, + (const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& callback), (override)); // V1_2 methods below. - MOCK_METHOD(Return<void>, getVersionString, (getVersionString_cb cb), (override)); - MOCK_METHOD(Return<void>, getType, (getType_cb cb), (override)); - MOCK_METHOD(Return<void>, getCapabilities_1_2, (getCapabilities_1_2_cb cb), (override)); - MOCK_METHOD(Return<void>, getSupportedExtensions, (getSupportedExtensions_cb cb), (override)); - MOCK_METHOD(Return<void>, getSupportedOperations_1_2, - (const V1_2::Model& model, getSupportedOperations_1_2_cb cb), (override)); - MOCK_METHOD(Return<void>, getNumberOfCacheFilesNeeded, (getNumberOfCacheFilesNeeded_cb cb), + MOCK_METHOD(hardware::Return<void>, getVersionString, (getVersionString_cb cb), (override)); + MOCK_METHOD(hardware::Return<void>, getType, (getType_cb cb), (override)); + MOCK_METHOD(hardware::Return<void>, getCapabilities_1_2, (getCapabilities_1_2_cb cb), + (override)); + MOCK_METHOD(hardware::Return<void>, getSupportedExtensions, (getSupportedExtensions_cb cb), (override)); - MOCK_METHOD(Return<V1_0::ErrorStatus>, prepareModel_1_2, - (const V1_2::Model& model, ExecutionPreference preference, - const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback), + MOCK_METHOD(hardware::Return<void>, getSupportedOperations_1_2, + (const V1_2::Model& model, getSupportedOperations_1_2_cb cb), (override)); + MOCK_METHOD(hardware::Return<void>, getNumberOfCacheFilesNeeded, + (getNumberOfCacheFilesNeeded_cb cb), (override)); + MOCK_METHOD(hardware::Return<V1_0::ErrorStatus>, prepareModel_1_2, + (const V1_2::Model& model, V1_1::ExecutionPreference preference, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const HalCacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback), (override)); - MOCK_METHOD(Return<V1_0::ErrorStatus>, prepareModelFromCache, - (const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache, - const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback), + MOCK_METHOD(hardware::Return<V1_0::ErrorStatus>, prepareModelFromCache, + (const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const HalCacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback), (override)); // V1_3 methods below. - MOCK_METHOD(Return<void>, getCapabilities_1_3, (getCapabilities_1_3_cb cb), (override)); - MOCK_METHOD(Return<void>, getSupportedOperations_1_3, + MOCK_METHOD(hardware::Return<void>, getCapabilities_1_3, (getCapabilities_1_3_cb cb), + (override)); + MOCK_METHOD(hardware::Return<void>, getSupportedOperations_1_3, (const V1_3::Model& model, getSupportedOperations_1_3_cb cb), (override)); - MOCK_METHOD(Return<V1_3::ErrorStatus>, prepareModel_1_3, - (const V1_3::Model& model, ExecutionPreference preference, Priority priority, - const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache, - const hidl_vec<hidl_handle>& dataCache, const CacheToken& token, - const sp<V1_3::IPreparedModelCallback>& callback), + MOCK_METHOD(hardware::Return<V1_3::ErrorStatus>, prepareModel_1_3, + (const V1_3::Model& model, V1_1::ExecutionPreference preference, + V1_3::Priority priority, const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const HalCacheToken& token, const sp<V1_3::IPreparedModelCallback>& callback), (override)); - MOCK_METHOD(Return<V1_3::ErrorStatus>, prepareModelFromCache_1_3, - (const OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache, - const hidl_vec<hidl_handle>& dataCache, const CacheToken& token, - const sp<V1_3::IPreparedModelCallback>& callback), + MOCK_METHOD(hardware::Return<V1_3::ErrorStatus>, prepareModelFromCache_1_3, + (const V1_3::OptionalTimePoint& deadline, + const hardware::hidl_vec<hardware::hidl_handle>& modelCache, + const hardware::hidl_vec<hardware::hidl_handle>& dataCache, + const HalCacheToken& token, const sp<V1_3::IPreparedModelCallback>& callback), (override)); - MOCK_METHOD(Return<void>, allocate, - (const BufferDesc& desc, const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, - const hidl_vec<BufferRole>& inputRoles, const hidl_vec<BufferRole>& outputRoles, - allocate_cb cb), + MOCK_METHOD(hardware::Return<void>, allocate, + (const V1_3::BufferDesc& desc, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels, + const hardware::hidl_vec<V1_3::BufferRole>& inputRoles, + const hardware::hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb), (override)); // Helper methods. - MOCK_METHOD(Return<bool>, linkToDeathRet, ()); + MOCK_METHOD(hardware::Return<bool>, linkToDeathRet, ()); void simulateCrash() { ASSERT_NE(nullptr, mDeathRecipient.get()); @@ -189,15 +217,15 @@ class MockDevice : public IDevice { private: // Members. - sp<hidl_death_recipient> mDeathRecipient; + sp<hardware::hidl_death_recipient> mDeathRecipient; }; -class MockPreparedModel : public IPreparedModel { +class MockPreparedModel : public V1_3::IPreparedModel { public: static sp<MockPreparedModel> create() { const sp<MockPreparedModel> mockPreparedModel = new MockPreparedModel(); - const auto linkToDeathRet_ret = []() -> Return<bool> { return true; }; + const auto linkToDeathRet_ret = []() -> hardware::Return<bool> { return true; }; ON_CALL(*mockPreparedModel, linkToDeathRet()).WillByDefault(Invoke(linkToDeathRet_ret)); // This EXPECT_CALL(...).Times(testing::AnyNumber()) calls are to @@ -208,27 +236,28 @@ class MockPreparedModel : public IPreparedModel { } // IBase methods below. - Return<bool> linkToDeath(const sp<hidl_death_recipient>& recipient, - uint64_t /*cookie*/) override { + hardware::Return<bool> linkToDeath(const sp<hardware::hidl_death_recipient>& recipient, + uint64_t /*cookie*/) override { mDeathRecipient = recipient; return linkToDeathRet(); } - MOCK_METHOD(Return<void>, ping, (), (override)); + MOCK_METHOD(hardware::Return<void>, ping, (), (override)); // V1_0 methods below. - MOCK_METHOD(Return<V1_0::ErrorStatus>, execute, + MOCK_METHOD(hardware::Return<V1_0::ErrorStatus>, execute, (const V1_0::Request& request, const sp<V1_0::IExecutionCallback>& callback), (override)); // V1_2 methods below. - MOCK_METHOD(Return<V1_0::ErrorStatus>, execute_1_2, - (const V1_0::Request& request, MeasureTiming measure, + MOCK_METHOD(hardware::Return<V1_0::ErrorStatus>, execute_1_2, + (const V1_0::Request& request, V1_2::MeasureTiming measure, const sp<V1_2::IExecutionCallback>& callback), (override)); - MOCK_METHOD(Return<void>, executeSynchronously, - (const V1_0::Request& request, MeasureTiming measure, executeSynchronously_cb cb), + MOCK_METHOD(hardware::Return<void>, executeSynchronously, + (const V1_0::Request& request, V1_2::MeasureTiming measure, + executeSynchronously_cb cb), (override)); - MOCK_METHOD(Return<void>, configureExecutionBurst, + MOCK_METHOD(hardware::Return<void>, configureExecutionBurst, (const sp<V1_2::IBurstCallback>& callback, const hardware::MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel, const hardware::MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, @@ -236,27 +265,28 @@ class MockPreparedModel : public IPreparedModel { (override)); // V1_3 methods below. - MOCK_METHOD(Return<ErrorStatus>, execute_1_3, - (const V1_3::Request& request, MeasureTiming measure, - const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const sp<IExecutionCallback>& callback), + MOCK_METHOD(hardware::Return<V1_3::ErrorStatus>, execute_1_3, + (const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const sp<V1_3::IExecutionCallback>& callback), (override)); - MOCK_METHOD(Return<void>, executeSynchronously_1_3, - (const V1_3::Request& request, MeasureTiming measure, - const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, + MOCK_METHOD(hardware::Return<void>, executeSynchronously_1_3, + (const V1_3::Request& request, V1_2::MeasureTiming measure, + const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb), (override)); - MOCK_METHOD(Return<void>, executeFenced, - (const V1_3::Request& request, const hidl_vec<hidl_handle>& waitFor, - MeasureTiming measure, const OptionalTimePoint& deadline, - const OptionalTimeoutDuration& loopTimeoutDuration, - const OptionalTimeoutDuration& duration, executeFenced_cb cb), + MOCK_METHOD(hardware::Return<void>, executeFenced, + (const V1_3::Request& request, + const hardware::hidl_vec<hardware::hidl_handle>& waitFor, + V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& deadline, + const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, + const V1_3::OptionalTimeoutDuration& duration, executeFenced_cb cb), (override)); // Helper methods. - MOCK_METHOD(Return<bool>, linkToDeathRet, ()); + MOCK_METHOD(hardware::Return<bool>, linkToDeathRet, ()); void simulateCrash() { ASSERT_NE(nullptr, mDeathRecipient.get()); @@ -271,27 +301,29 @@ class MockPreparedModel : public IPreparedModel { private: // Members. - sp<hidl_death_recipient> mDeathRecipient; + sp<hardware::hidl_death_recipient> mDeathRecipient; }; class MockBurstContext : public V1_2::IBurstContext { public: // V1_2 methods below. - MOCK_METHOD(Return<void>, freeMemory, (int32_t slot), (override)); + MOCK_METHOD(hardware::Return<void>, freeMemory, (int32_t slot), (override)); }; -class MockFencedExecutionCallback : public IFencedExecutionCallback { +class MockFencedExecutionCallback : public V1_3::IFencedExecutionCallback { public: // V1_3 methods below. - MOCK_METHOD(Return<void>, getExecutionInfo, (getExecutionInfo_cb cb), (override)); + MOCK_METHOD(hardware::Return<void>, getExecutionInfo, (getExecutionInfo_cb cb), (override)); }; -class MockBuffer : public IBuffer { +class MockBuffer : public V1_3::IBuffer { public: // V1_3 methods below. - MOCK_METHOD(Return<ErrorStatus>, copyTo, (const hidl_memory& dst), (override)); - MOCK_METHOD(Return<ErrorStatus>, copyFrom, - (const hidl_memory& src, const hidl_vec<uint32_t>& dimensions), (override)); + MOCK_METHOD(hardware::Return<V1_3::ErrorStatus>, copyTo, (const hardware::hidl_memory& dst), + (override)); + MOCK_METHOD(hardware::Return<V1_3::ErrorStatus>, copyFrom, + (const hardware::hidl_memory& src, const hardware::hidl_vec<uint32_t>& dimensions), + (override)); }; enum class Version { V1_0, V1_1, V1_2, V1_3, MOCK }; @@ -315,18 +347,19 @@ sp<V1_0::IDevice> adaptAs(const sp<MockDevice>& mockDevice, Version version) { auto makePreparedModelReturn(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, const sp<MockPreparedModel>& preparedModel) { - return [launchStatus, returnStatus, preparedModel]( - const V1_0::Model& /*model*/, - const sp<V1_0::IPreparedModelCallback>& cb) -> Return<V1_0::ErrorStatus> { + return [launchStatus, returnStatus, preparedModel](const V1_0::Model& /*model*/, + const sp<V1_0::IPreparedModelCallback>& cb) + -> hardware::Return<V1_0::ErrorStatus> { cb->notify(returnStatus, preparedModel).isOk(); return launchStatus; }; } auto makePreparedModel_1_1Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, const sp<MockPreparedModel>& preparedModel) { - return [launchStatus, returnStatus, preparedModel]( - const V1_1::Model& /*model*/, ExecutionPreference /*preference*/, - const sp<V1_0::IPreparedModelCallback>& cb) -> Return<V1_0::ErrorStatus> { + return [launchStatus, returnStatus, preparedModel](const V1_1::Model& /*model*/, + V1_1::ExecutionPreference /*preference*/, + const sp<V1_0::IPreparedModelCallback>& cb) + -> hardware::Return<V1_0::ErrorStatus> { cb->notify(returnStatus, preparedModel).isOk(); return launchStatus; }; @@ -334,9 +367,10 @@ auto makePreparedModel_1_1Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStat auto makePreparedModel_1_2Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, const sp<MockPreparedModel>& preparedModel) { return [launchStatus, returnStatus, preparedModel]( - const V1_2::Model& /*model*/, ExecutionPreference /*preference*/, + const V1_2::Model& /*model*/, V1_1::ExecutionPreference /*preference*/, const auto& /*modelCache*/, const auto& /*dataCache*/, const auto& /*token*/, - const sp<V1_2::IPreparedModelCallback>& cb) -> Return<V1_0::ErrorStatus> { + const sp<V1_2::IPreparedModelCallback>& cb) + -> hardware::Return<V1_0::ErrorStatus> { cb->notify_1_2(returnStatus, preparedModel).isOk(); return launchStatus; }; @@ -344,11 +378,12 @@ auto makePreparedModel_1_2Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStat auto makePreparedModel_1_3Return(V1_3::ErrorStatus launchStatus, V1_3::ErrorStatus returnStatus, const sp<MockPreparedModel>& preparedModel) { return [launchStatus, returnStatus, preparedModel]( - const V1_3::Model& /*model*/, ExecutionPreference /*preference*/, - Priority /*priority*/, const OptionalTimePoint& /*deadline*/, - const hidl_vec<hidl_handle>& /*modelCache*/, - const hidl_vec<hidl_handle>& /*dataCache*/, const CacheToken& /*token*/, - const sp<V1_3::IPreparedModelCallback>& cb) -> Return<V1_3::ErrorStatus> { + const V1_3::Model& /*model*/, V1_1::ExecutionPreference /*preference*/, + V1_3::Priority /*priority*/, const V1_3::OptionalTimePoint& /*deadline*/, + const hardware::hidl_vec<hardware::hidl_handle>& /*modelCache*/, + const hardware::hidl_vec<hardware::hidl_handle>& /*dataCache*/, + const HalCacheToken& /*token*/, const sp<V1_3::IPreparedModelCallback>& cb) + -> hardware::Return<V1_3::ErrorStatus> { cb->notify_1_3(returnStatus, preparedModel).isOk(); return launchStatus; }; @@ -357,51 +392,53 @@ auto makePreparedModel_1_3Return(V1_3::ErrorStatus launchStatus, V1_3::ErrorStat auto makeExecuteReturn(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus) { return [launchStatus, returnStatus]( const V1_0::Request& /*request*/, - const sp<V1_0::IExecutionCallback>& cb) -> Return<V1_0::ErrorStatus> { + const sp<V1_0::IExecutionCallback>& cb) -> hardware::Return<V1_0::ErrorStatus> { cb->notify(returnStatus); return launchStatus; }; } auto makeExecute_1_2Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, - const std::vector<OutputShape>& outputShapes, const Timing& timing) { + const std::vector<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { return [launchStatus, returnStatus, outputShapes, timing]( - const V1_0::Request& /*request*/, MeasureTiming /*measureTiming*/, - const sp<V1_2::IExecutionCallback>& cb) -> Return<V1_0::ErrorStatus> { + const V1_0::Request& /*request*/, V1_2::MeasureTiming /*measureTiming*/, + const sp<V1_2::IExecutionCallback>& cb) -> hardware::Return<V1_0::ErrorStatus> { cb->notify_1_2(returnStatus, outputShapes, timing); return launchStatus; }; } auto makeExecute_1_3Return(V1_3::ErrorStatus launchStatus, V1_3::ErrorStatus returnStatus, - const std::vector<OutputShape>& outputShapes, const Timing& timing) { + const std::vector<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { return [launchStatus, returnStatus, outputShapes, timing]( - const V1_3::Request& /*request*/, MeasureTiming /*measureTiming*/, - const OptionalTimePoint& /*deadline*/, - const OptionalTimeoutDuration& /*loopTimeoutDuration*/, - const sp<V1_3::IExecutionCallback>& cb) -> Return<V1_3::ErrorStatus> { + const V1_3::Request& /*request*/, V1_2::MeasureTiming /*measureTiming*/, + const V1_3::OptionalTimePoint& /*deadline*/, + const V1_3::OptionalTimeoutDuration& /*loopTimeoutDuration*/, + const sp<V1_3::IExecutionCallback>& cb) -> hardware::Return<V1_3::ErrorStatus> { cb->notify_1_3(returnStatus, outputShapes, timing); return launchStatus; }; } auto makeExecuteSynchronouslyReturn(V1_0::ErrorStatus status, - const std::vector<OutputShape>& outputShapes, - const Timing& timing) { + const std::vector<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { return [status, outputShapes, timing](const V1_0::Request& /*request*/, - MeasureTiming /*measureTiming*/, + V1_2::MeasureTiming /*measureTiming*/, const V1_2::IPreparedModel::executeSynchronously_cb& cb) { cb(status, outputShapes, timing); - return Void(); + return hardware::Void(); }; } auto makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus status, - const std::vector<OutputShape>& outputShapes, - const Timing& timing) { + const std::vector<V1_2::OutputShape>& outputShapes, + const V1_2::Timing& timing) { return [status, outputShapes, timing]( - const V1_3::Request& /*request*/, MeasureTiming /*measureTiming*/, - const OptionalTimePoint& /*deadline*/, - const OptionalTimeoutDuration& /*loopTimeoutDuration*/, + const V1_3::Request& /*request*/, V1_2::MeasureTiming /*measureTiming*/, + const V1_3::OptionalTimePoint& /*deadline*/, + const V1_3::OptionalTimeoutDuration& /*loopTimeoutDuration*/, const V1_3::IPreparedModel::executeSynchronously_1_3_cb& cb) { cb(status, outputShapes, timing); - return Void(); + return hardware::Void(); }; } auto makeConfigureExecutionBurst(V1_0::ErrorStatus status, @@ -412,19 +449,20 @@ auto makeConfigureExecutionBurst(V1_0::ErrorStatus status, const hardware::MQDescriptorSync<V1_2::FmqResultDatum>& /*resultChannel*/, V1_2::IPreparedModel::configureExecutionBurst_cb cb) { cb(status, burstContext); - return Void(); + return hardware::Void(); }; } -auto makeExecuteFencedReturn(V1_3::ErrorStatus status, const hidl_handle& syncFence, - const sp<IFencedExecutionCallback>& dispatchCallback) { +auto makeExecuteFencedReturn(V1_3::ErrorStatus status, const hardware::hidl_handle& syncFence, + const sp<V1_3::IFencedExecutionCallback>& dispatchCallback) { return [status, syncFence, dispatchCallback]( - const V1_3::Request& /*request*/, const hidl_vec<hidl_handle>& /*waitFor*/, - MeasureTiming /*measure*/, const OptionalTimePoint& /*deadline*/, - const OptionalTimeoutDuration& /*loopTimeoutDuration*/, - const OptionalTimeoutDuration& /*duration*/, + const V1_3::Request& /*request*/, + const hardware::hidl_vec<hardware::hidl_handle>& /*waitFor*/, + V1_2::MeasureTiming /*measure*/, const V1_3::OptionalTimePoint& /*deadline*/, + const V1_3::OptionalTimeoutDuration& /*loopTimeoutDuration*/, + const V1_3::OptionalTimeoutDuration& /*duration*/, V1_3::IPreparedModel::executeFenced_cb cb) { cb(status, syncFence, dispatchCallback); - return Void(); + return hardware::Void(); }; } @@ -516,7 +554,7 @@ std::shared_ptr<VersionedIDevice> makeVersionedIDeviceFrom(const sp<MockDevice>& const auto device = adaptAs(mockDevice, version); ON_CALL(*mockDeviceFactory, Call(_)).WillByDefault(testing::Return(device)); EXPECT_CALL(*mockDeviceFactory, Call(/*blocking=*/true)).Times(testing::AtLeast(1)); - const DeviceFactory makeDevice = mockDeviceFactory->AsStdFunction(); + const HalDeviceFactory makeDevice = mockDeviceFactory->AsStdFunction(); return VersionedIDevice::create("MockDevice", makeDevice); } @@ -566,7 +604,7 @@ class VersionedIDeviceMockTest : public VersionedIDeviceInitializedTest<Version: TEST_F(VersionedIDeviceInitializationTest, creationFailure) { // setup failure EXPECT_CALL(*kMockMakeDevice, Call(_)).Times(1).WillOnce(testing::Return(nullptr)); - const DeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); + const HalDeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); // run test const auto device = VersionedIDevice::create("MockDevice", makeDevice); @@ -581,7 +619,7 @@ TEST_F(VersionedIDeviceInitializationTest, linkToDeathTransportFailure) { .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); EXPECT_CALL(*kMockMakeDevice, Call(_)).Times(1).WillOnce(testing::Return(kMockDevice)); - const DeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); + const HalDeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); // run test const auto device = VersionedIDevice::create("MockDevice", makeDevice); @@ -592,10 +630,10 @@ TEST_F(VersionedIDeviceInitializationTest, linkToDeathTransportFailure) { TEST_F(VersionedIDeviceInitializationTest, linkToDeathReturnError) { // setup failure - const auto ret = []() -> Return<bool> { return false; }; + const auto ret = []() -> hardware::Return<bool> { return false; }; EXPECT_CALL(*kMockMakeDevice, Call(_)).Times(1).WillOnce(testing::Return(kMockDevice)); EXPECT_CALL(*kMockDevice, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret)); - const DeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); + const HalDeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); // run test const auto device = VersionedIDevice::create("MockDevice", makeDevice); @@ -666,7 +704,8 @@ TEST_F(VersionedIDeviceInitializationTest, getVersionStringFailure) { TEST_F(VersionedIDeviceInitializationTest, getTypeFailure) { // setup failure - const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, DeviceType::OTHER); + const auto ret = + makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_2::DeviceType::OTHER); EXPECT_CALL(*kMockDevice, getType(_)).Times(1).WillOnce(Invoke(ret)); // run test @@ -678,7 +717,8 @@ TEST_F(VersionedIDeviceInitializationTest, getTypeFailure) { TEST_F(VersionedIDeviceInitializationTest, getSupportedExtensionsFailure) { // setup failure - const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, hidl_vec<Extension>{}); + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, + hardware::hidl_vec<V1_2::Extension>{}); EXPECT_CALL(*kMockDevice, getSupportedExtensions(_)).Times(1).WillOnce(Invoke(ret)); // run test @@ -839,9 +879,11 @@ TEST_F(VersionedIDeviceV1_0Test, getCapabilities) { const auto cached = kDevice->getCapabilities(); // verify success - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); - EXPECT_LT(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_LT(0u, capabilities.operandPerformance.asVector().size()); EXPECT_EQ(cached, capabilities); } @@ -851,9 +893,11 @@ TEST_F(VersionedIDeviceV1_1Test, getCapabilities) { const auto cached = kDevice->getCapabilities(); // verify success - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); - EXPECT_LT(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_LT(0u, capabilities.operandPerformance.asVector().size()); EXPECT_EQ(cached, capabilities); } @@ -863,9 +907,11 @@ TEST_F(VersionedIDeviceV1_2Test, getCapabilities) { const auto cached = kDevice->getCapabilities(); // verify success - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); - EXPECT_EQ(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_EQ(0u, capabilities.operandPerformance.asVector().size()); EXPECT_EQ(cached, capabilities); } @@ -875,9 +921,11 @@ TEST_F(VersionedIDeviceV1_3Test, getCapabilities) { const auto cached = kDevice->getCapabilities(); // verify success - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); - EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); - EXPECT_EQ(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(Capabilities::PerformanceInfo{}, + capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_EQ(0u, capabilities.operandPerformance.asVector().size()); EXPECT_EQ(cached, capabilities); } @@ -1107,16 +1155,16 @@ TEST_F(VersionedIDeviceV1_0Test, getSupportedOperations) { // setup call const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_0::ErrorStatus::NONE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify success - EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(ErrorStatus::NONE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1124,16 +1172,16 @@ TEST_F(VersionedIDeviceV1_1Test, getSupportedOperations) { // setup call const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_0::ErrorStatus::NONE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations_1_1(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify success - EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(ErrorStatus::NONE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1141,16 +1189,16 @@ TEST_F(VersionedIDeviceV1_2Test, getSupportedOperations) { // setup call const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_0::ErrorStatus::NONE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations_1_2(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify success - EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(ErrorStatus::NONE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1158,16 +1206,16 @@ TEST_F(VersionedIDeviceV1_3Test, getSupportedOperations) { // setup call const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_3::ErrorStatus::NONE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations_1_3(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify success - EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(ErrorStatus::NONE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1179,7 +1227,7 @@ TEST_F(VersionedIDeviceV1_0Test, prepareModel) { EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify success @@ -1195,7 +1243,7 @@ TEST_F(VersionedIDeviceV1_1Test, prepareModel) { EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify success @@ -1211,7 +1259,7 @@ TEST_F(VersionedIDeviceV1_2Test, prepareModel) { EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify success @@ -1229,7 +1277,7 @@ TEST_F(VersionedIDeviceV1_3Test, prepareModel) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify success @@ -1271,13 +1319,14 @@ TEST_F(VersionedIDeviceV1_3Test, allocate) { // setup call const sp<MockBuffer> mockBuffer = new MockBuffer(); constexpr uint32_t mockToken = 1; - const auto ret = [mockBuffer](const BufferDesc& /*desc*/, - const hidl_vec<sp<V1_3::IPreparedModel>>& /*preparedModels*/, - const hidl_vec<BufferRole>& /*inputRoles*/, - const hidl_vec<BufferRole>& /*outputRoles*/, - V1_3::IDevice::allocate_cb cb) -> Return<void> { + const auto ret = [mockBuffer]( + const V1_3::BufferDesc& /*desc*/, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& /*preparedModels*/, + const hardware::hidl_vec<V1_3::BufferRole>& /*inputRoles*/, + const hardware::hidl_vec<V1_3::BufferRole>& /*outputRoles*/, + V1_3::IDevice::allocate_cb cb) -> hardware::Return<void> { cb(V1_3::ErrorStatus::NONE, mockBuffer, mockToken); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, allocate(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); @@ -1292,7 +1341,7 @@ TEST_F(VersionedIDeviceV1_3Test, allocate) { TEST_F(VersionedIDeviceMockTest, wait) { // setup call - const auto ret = []() -> Return<void> { return {}; }; + const auto ret = []() -> hardware::Return<void> { return {}; }; EXPECT_CALL(*kMockDevice, ping()).Times(1).WillOnce(Invoke(ret)); // run test @@ -1308,16 +1357,16 @@ TEST_F(VersionedIDeviceV1_0Test, getSupportedOperationsFailure) { // setup failure const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1325,16 +1374,16 @@ TEST_F(VersionedIDeviceV1_1Test, getSupportedOperationsFailure) { // setup failure const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations_1_1(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1342,16 +1391,16 @@ TEST_F(VersionedIDeviceV1_2Test, getSupportedOperationsFailure) { // setup failure const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations_1_2(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1359,16 +1408,16 @@ TEST_F(VersionedIDeviceV1_3Test, getSupportedOperationsFailure) { // setup failure const auto ret = [](const auto& /*model*/, const auto cb) { cb(V1_3::ErrorStatus::GENERAL_FAILURE, {}); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, getSupportedOperations_1_3(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1380,7 +1429,7 @@ TEST_F(VersionedIDeviceV1_0Test, prepareModelLaunchFailure) { EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1396,7 +1445,7 @@ TEST_F(VersionedIDeviceV1_1Test, prepareModelLaunchFailure) { EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1412,7 +1461,7 @@ TEST_F(VersionedIDeviceV1_2Test, prepareModelLaunchFailure) { EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1430,7 +1479,7 @@ TEST_F(VersionedIDeviceV1_3Test, prepareModelLaunchFailure) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1446,7 +1495,7 @@ TEST_F(VersionedIDeviceV1_0Test, prepareModelReturnFailure) { EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1462,7 +1511,7 @@ TEST_F(VersionedIDeviceV1_1Test, prepareModelReturnFailure) { EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1478,7 +1527,7 @@ TEST_F(VersionedIDeviceV1_2Test, prepareModelReturnFailure) { EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1496,7 +1545,7 @@ TEST_F(VersionedIDeviceV1_3Test, prepareModelReturnFailure) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1512,7 +1561,7 @@ TEST_F(VersionedIDeviceV1_0Test, prepareModelNullptrError) { EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1528,7 +1577,7 @@ TEST_F(VersionedIDeviceV1_1Test, prepareModelNullptrError) { EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1544,7 +1593,7 @@ TEST_F(VersionedIDeviceV1_2Test, prepareModelNullptrError) { EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1562,7 +1611,7 @@ TEST_F(VersionedIDeviceV1_3Test, prepareModelNullptrError) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1572,13 +1621,13 @@ TEST_F(VersionedIDeviceV1_3Test, prepareModelNullptrError) { TEST_F(VersionedIDeviceV1_3Test, allocateFailure) { // setup failure - const auto ret = [](const BufferDesc& /*desc*/, - const hidl_vec<sp<V1_3::IPreparedModel>>& /*preparedModels*/, - const hidl_vec<BufferRole>& /*inputRoles*/, - const hidl_vec<BufferRole>& /*outputRoles*/, - V1_3::IDevice::allocate_cb cb) -> Return<void> { + const auto ret = [](const V1_3::BufferDesc& /*desc*/, + const hardware::hidl_vec<sp<V1_3::IPreparedModel>>& /*preparedModels*/, + const hardware::hidl_vec<V1_3::BufferRole>& /*inputRoles*/, + const hardware::hidl_vec<V1_3::BufferRole>& /*outputRoles*/, + V1_3::IDevice::allocate_cb cb) -> hardware::Return<void> { cb(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, 0); - return Void(); + return hardware::Void(); }; EXPECT_CALL(*kMockDevice, allocate(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); @@ -1600,11 +1649,11 @@ TEST_F(VersionedIDeviceV1_0Test, getSupportedOperationsTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1615,11 +1664,11 @@ TEST_F(VersionedIDeviceV1_1Test, getSupportedOperationsTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1630,11 +1679,11 @@ TEST_F(VersionedIDeviceV1_2Test, getSupportedOperationsTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1645,11 +1694,11 @@ TEST_F(VersionedIDeviceV1_3Test, getSupportedOperationsTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto metaModel = MetaModel(Model{}, /*strictSlicing=*/true); const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); // verify failure - EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(ErrorStatus::GENERAL_FAILURE, resultCode); EXPECT_EQ(0u, supportedOperations.size()); } @@ -1660,7 +1709,7 @@ TEST_F(VersionedIDeviceV1_0Test, prepareModelTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1675,7 +1724,7 @@ TEST_F(VersionedIDeviceV1_1Test, prepareModelTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1690,7 +1739,7 @@ TEST_F(VersionedIDeviceV1_2Test, prepareModelTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1705,7 +1754,7 @@ TEST_F(VersionedIDeviceV1_3Test, prepareModelTransportFailure) { .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1767,7 +1816,7 @@ TEST_F(VersionedIDeviceMockTest, DISABLED_prepareModelRecoverCrash) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify success @@ -1788,7 +1837,7 @@ TEST_F(VersionedIDeviceMockTest, prepareModelFullCrash) { .WillOnce(testing::Return(nullptr)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1798,7 +1847,7 @@ TEST_F(VersionedIDeviceMockTest, prepareModelFullCrash) { TEST_F(VersionedIDeviceMockTest, prepareModelAsyncCrash) { // setup failure - const auto ret = [this]() -> Return<V1_3::ErrorStatus> { + const auto ret = [this]() -> hardware::Return<V1_3::ErrorStatus> { kMockDevice->simulateCrash(); return V1_3::ErrorStatus::NONE; }; @@ -1807,7 +1856,7 @@ TEST_F(VersionedIDeviceMockTest, prepareModelAsyncCrash) { .WillOnce(InvokeWithoutArgs(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1842,7 +1891,7 @@ TEST_F(VersionedIDeviceMockTest, waitRecoverCrash) { .WillOnce(testing::Return(mockRecoveredDevice)); // setup recovered device calls - const auto ret = []() -> Return<bool> { return true; }; + const auto ret = []() -> hardware::Return<bool> { return true; }; EXPECT_CALL(*mockRecoveredDevice, linkToDeathRet()).Times(1).WillOnce(Invoke(ret)); // run test @@ -1903,7 +1952,7 @@ std::shared_ptr<VersionedIPreparedModel> makeVersionedIPreparedModelSuccessfulIn EXPECT_CALL(*mockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(testing::AnyNumber()); EXPECT_CALL(*mockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)).Times(testing::AnyNumber()); - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = device.prepareModel(makeModel, {}, {}, {}, {}, {}); CHECK_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); @@ -1948,7 +1997,7 @@ TEST_F(VersionedIPreparedModelInitializationTest, linkToDeathTransportFailure) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1968,7 +2017,7 @@ TEST_F(VersionedIPreparedModelInitializationTest, linkToDeathDeadObject) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -1980,7 +2029,7 @@ TEST_F(VersionedIPreparedModelInitializationTest, linkToDeathReturnError) { // setup failure EXPECT_CALL(*kMockPreparedModel, linkToDeathRet()) .Times(1) - .WillOnce(InvokeWithoutArgs([]() -> Return<bool> { return false; })); + .WillOnce(InvokeWithoutArgs([]() -> hardware::Return<bool> { return false; })); const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, kMockPreparedModel); EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) @@ -1988,7 +2037,7 @@ TEST_F(VersionedIPreparedModelInitializationTest, linkToDeathReturnError) { .WillOnce(Invoke(ret)); // run test - const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const ModelFactory makeModel = [] { return Model{}; }; const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); // verify failure @@ -2030,8 +2079,8 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeAsync) { TEST_F(VersionedIPreparedModelV1_2Test, executeAsync) { // setup call - const auto ret = - makeExecute_1_2Return(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, {}, kNoTiming); + const auto ret = makeExecute_1_2Return(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, {}, + kNoTiming12); EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2046,8 +2095,8 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeAsync) { TEST_F(VersionedIPreparedModelV1_3Test, executeAsync) { // setup call - const auto ret = - makeExecute_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, {}, kNoTiming); + const auto ret = makeExecute_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, {}, + kNoTiming12); EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2092,7 +2141,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executePreferSync) { TEST_F(VersionedIPreparedModelV1_2Test, executePreferSync) { // setup call - const auto ret = makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::NONE, {}, kNoTiming); + const auto ret = makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::NONE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2107,7 +2156,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executePreferSync) { TEST_F(VersionedIPreparedModelV1_3Test, executePreferSync) { // setup call - const auto ret = makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus::NONE, {}, kNoTiming); + const auto ret = makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus::NONE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, executeSynchronously_1_3(_, _, _, _, _)) .Times(1) .WillOnce(Invoke(ret)); @@ -2156,7 +2205,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFenced) { TEST_F(VersionedIPreparedModelV1_2Test, executeFenced) { // setup call - const auto ret = makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::NONE, {}, kNoTiming); + const auto ret = makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::NONE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2173,8 +2222,8 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFenced) { TEST_F(VersionedIPreparedModelV1_3Test, executeFenced) { // setup call auto memory = allocateSharedMemory(4); - hidl_handle fakeSyncFence(memory.handle()); - const sp<IFencedExecutionCallback> callback = new MockFencedExecutionCallback(); + hardware::hidl_handle fakeSyncFence(memory.handle()); + const sp<V1_3::IFencedExecutionCallback> callback = new MockFencedExecutionCallback(); const auto ret = makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, fakeSyncFence, callback); EXPECT_CALL(*kMockPreparedModel, executeFenced(_, _, _, _, _, _, _)) .Times(1) @@ -2276,7 +2325,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeAsyncLaunchFailure) { TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncLaunchFailure) { // setup failure const auto ret = makeExecute_1_2Return(V1_0::ErrorStatus::GENERAL_FAILURE, - V1_0::ErrorStatus::NONE, {}, kNoTiming); + V1_0::ErrorStatus::NONE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2292,7 +2341,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncLaunchFailure) { TEST_F(VersionedIPreparedModelV1_3Test, executeAsyncLaunchFailure) { // setup failure const auto ret = makeExecute_1_3Return(V1_3::ErrorStatus::GENERAL_FAILURE, - V1_3::ErrorStatus::NONE, {}, kNoTiming); + V1_3::ErrorStatus::NONE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2338,7 +2387,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeAsyncReturnFailure) { TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncReturnFailure) { // setup failure const auto ret = makeExecute_1_2Return(V1_0::ErrorStatus::NONE, - V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2354,7 +2403,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncReturnFailure) { TEST_F(VersionedIPreparedModelV1_3Test, executeAsyncReturnFailure) { // setup failure const auto ret = makeExecute_1_3Return(V1_3::ErrorStatus::NONE, - V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2402,7 +2451,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executePreferSyncFailure) { TEST_F(VersionedIPreparedModelV1_2Test, executePreferSyncFailure) { // setup failure const auto ret = - makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2418,7 +2467,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executePreferSyncFailure) { TEST_F(VersionedIPreparedModelV1_3Test, executePreferSyncFailure) { // setup failure const auto ret = - makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, executeSynchronously_1_3(_, _, _, _, _)) .Times(1) .WillOnce(Invoke(ret)); @@ -2470,7 +2519,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFencedFailure) { TEST_F(VersionedIPreparedModelV1_2Test, executeFencedFailure) { // setup failure const auto ret = - makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming12); EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); // run test @@ -2487,8 +2536,8 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFencedFailure) { TEST_F(VersionedIPreparedModelV1_3Test, executeFencedFailure) { // setup failure auto memory = allocateSharedMemory(4); - hidl_handle fakeSyncFence(memory.handle()); - const sp<IFencedExecutionCallback> callback = new MockFencedExecutionCallback(); + hardware::hidl_handle fakeSyncFence(memory.handle()); + const sp<V1_3::IFencedExecutionCallback> callback = new MockFencedExecutionCallback(); const auto ret = makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, fakeSyncFence, callback); EXPECT_CALL(*kMockPreparedModel, executeFenced(_, _, _, _, _, _, _)) @@ -2894,7 +2943,7 @@ TEST_F(VersionedIPreparedModelV1_3Test, executePreferSyncCrash) { TEST_F(VersionedIPreparedModelMockTest, executeAsyncReturnCrash) { // setup failure - const auto ret = [this]() -> Return<V1_3::ErrorStatus> { + const auto ret = [this]() -> hardware::Return<V1_3::ErrorStatus> { kMockPreparedModel->simulateCrash(); return V1_3::ErrorStatus::NONE; }; diff --git a/nn/runtime/test/android_fuzzing/Converter.cpp b/nn/runtime/test/android_fuzzing/Converter.cpp index ca853aefc..c2fc354fa 100644 --- a/nn/runtime/test/android_fuzzing/Converter.cpp +++ b/nn/runtime/test/android_fuzzing/Converter.cpp @@ -29,39 +29,38 @@ namespace android::nn::fuzz { namespace { using namespace test_helper; -using namespace android_nn_fuzz; constexpr uint32_t kMaxSize = 65536; -TestOperandType convert(OperandType type) { +TestOperandType convert(android_nn_fuzz::OperandType type) { return static_cast<TestOperandType>(type); } -TestOperationType convert(OperationType type) { +TestOperationType convert(android_nn_fuzz::OperationType type) { return static_cast<TestOperationType>(type); } -TestOperandLifeTime convert(OperandLifeTime lifetime) { +TestOperandLifeTime convert(android_nn_fuzz::OperandLifeTime lifetime) { return static_cast<TestOperandLifeTime>(lifetime); } -std::vector<float> convert(const Scales& scales) { +std::vector<float> convert(const android_nn_fuzz::Scales& scales) { const auto& repeatedScale = scales.scale(); return std::vector<float>(repeatedScale.begin(), repeatedScale.end()); } -TestSymmPerChannelQuantParams convert(const SymmPerChannelQuantParams& params) { +TestSymmPerChannelQuantParams convert(const android_nn_fuzz::SymmPerChannelQuantParams& params) { std::vector<float> scales = convert(params.scales()); const uint32_t channelDim = params.channel_dim(); return {.scales = std::move(scales), .channelDim = channelDim}; } -std::vector<uint32_t> convert(const Dimensions& dimensions) { +std::vector<uint32_t> convert(const android_nn_fuzz::Dimensions& dimensions) { const auto& repeatedDimension = dimensions.dimension(); return std::vector<uint32_t>(repeatedDimension.begin(), repeatedDimension.end()); } -TestBuffer convert(size_t size, const Buffer& buffer) { +TestBuffer convert(size_t size, const android_nn_fuzz::Buffer& buffer) { if (size == 0) { return TestBuffer(); } @@ -70,7 +69,7 @@ TestBuffer convert(size_t size, const Buffer& buffer) { return TestBuffer::createRandom(size % kMaxSize, &generator); } -TestOperand convert(const Operand& operand) { +TestOperand convert(const android_nn_fuzz::Operand& operand) { const TestOperandType type = convert(operand.type()); std::vector<uint32_t> dimensions = convert(operand.dimensions()); const float scale = operand.scale(); @@ -79,7 +78,7 @@ TestOperand convert(const Operand& operand) { auto channelQuant = convert(operand.channel_quant()); const bool isIgnored = false; - const auto halType = static_cast<hal::OperandType>(type); + const auto halType = static_cast<V1_3::OperandType>(type); const bool willOverflow = nonExtensionOperandSizeOfDataOverflowsUInt32(halType, dimensions); const bool makeEmpty = (lifetime == TestOperandLifeTime::NO_VALUE || lifetime == TestOperandLifeTime::TEMPORARY_VARIABLE || willOverflow); @@ -97,7 +96,7 @@ TestOperand convert(const Operand& operand) { .data = std::move(data)}; } -std::vector<TestOperand> convert(const Operands& operands) { +std::vector<TestOperand> convert(const android_nn_fuzz::Operands& operands) { std::vector<TestOperand> testOperands; testOperands.reserve(operands.operand_size()); const auto& repeatedOperand = operands.operand(); @@ -106,19 +105,19 @@ std::vector<TestOperand> convert(const Operands& operands) { return testOperands; } -std::vector<uint32_t> convert(const Indexes& indexes) { +std::vector<uint32_t> convert(const android_nn_fuzz::Indexes& indexes) { const auto& repeatedIndex = indexes.index(); return std::vector<uint32_t>(repeatedIndex.begin(), repeatedIndex.end()); } -TestOperation convert(const Operation& operation) { +TestOperation convert(const android_nn_fuzz::Operation& operation) { const TestOperationType type = convert(operation.type()); std::vector<uint32_t> inputs = convert(operation.inputs()); std::vector<uint32_t> outputs = convert(operation.outputs()); return {.type = type, .inputs = std::move(inputs), .outputs = std::move(outputs)}; } -std::vector<TestOperation> convert(const Operations& operations) { +std::vector<TestOperation> convert(const android_nn_fuzz::Operations& operations) { std::vector<TestOperation> testOperations; testOperations.reserve(operations.operation_size()); const auto& repeatedOperation = operations.operation(); @@ -142,7 +141,7 @@ void calculateNumberOfConsumers(const std::vector<TestOperation>& operations, std::for_each(operations.begin(), operations.end(), addAllConsumers); } -TestModel convert(const Model& model) { +TestModel convert(const android_nn_fuzz::Model& model) { std::vector<TestOperand> operands = convert(model.operands()); std::vector<TestOperation> operations = convert(model.operations()); std::vector<uint32_t> inputIndexes = convert(model.input_indexes()); @@ -161,7 +160,7 @@ TestModel convert(const Model& model) { } // anonymous namespace -TestModel convertToTestModel(const Test& model) { +TestModel convertToTestModel(const android_nn_fuzz::Test& model) { return convert(model.model()); } diff --git a/nn/runtime/test/android_fuzzing/FuzzHarness.cpp b/nn/runtime/test/android_fuzzing/FuzzHarness.cpp index 3d787d68f..76c34a75a 100644 --- a/nn/runtime/test/android_fuzzing/FuzzHarness.cpp +++ b/nn/runtime/test/android_fuzzing/FuzzHarness.cpp @@ -31,7 +31,7 @@ namespace { using ::android::nn::nonExtensionOperandSizeOfDataOverflowsUInt32; using ::android::nn::fuzz::convertToTestModel; -using ::android::nn::hal::OperandType; +using ::android::nn::V1_3::OperandType; using ::test_helper::TestModel; using ::test_helper::TestOperand; diff --git a/nn/runtime/test/android_fuzzing/GenerateCorpus.cpp b/nn/runtime/test/android_fuzzing/GenerateCorpus.cpp index 2f72b9da4..783b66092 100644 --- a/nn/runtime/test/android_fuzzing/GenerateCorpus.cpp +++ b/nn/runtime/test/android_fuzzing/GenerateCorpus.cpp @@ -41,8 +41,8 @@ OperationType convert(TestOperationType type) { return static_cast<OperationType>(type); } -OperandLifeTime convert(TestOperandLifeTime lifetime) { - return static_cast<OperandLifeTime>(lifetime); +Operand::LifeTime convert(TestOperandLifeTime lifetime) { + return static_cast<Operand::LifeTime>(lifetime); } Scales convert(const std::vector<float>& scales) { diff --git a/nn/runtime/test/fibonacci_extension/FibonacciDriver.cpp b/nn/runtime/test/fibonacci_extension/FibonacciDriver.cpp index c48829867..66023c1db 100644 --- a/nn/runtime/test/fibonacci_extension/FibonacciDriver.cpp +++ b/nn/runtime/test/fibonacci_extension/FibonacciDriver.cpp @@ -20,6 +20,7 @@ #include <vector> +#include <nnapi/Types.h> #include "FibonacciExtension.h" #include "HalInterfaces.h" #include "NeuralNetworksExtensions.h" @@ -33,10 +34,7 @@ namespace nn { namespace sample_driver { namespace { -using namespace hal; - -const uint8_t kLowBitsType = static_cast<uint8_t>(ExtensionTypeEncoding::LOW_BITS_TYPE); -const uint32_t kTypeWithinExtensionMask = (1 << kLowBitsType) - 1; +const uint32_t kTypeWithinExtensionMask = (1 << kExtensionTypeBits) - 1; namespace fibonacci_op { @@ -48,22 +46,22 @@ constexpr uint32_t kInputN = 0; constexpr uint32_t kNumOutputs = 1; constexpr uint32_t kOutputTensor = 0; -bool getFibonacciExtensionPrefix(const Model& model, uint16_t* prefix) { +bool getFibonacciExtensionPrefix(const V1_3::Model& model, uint16_t* prefix) { NN_RET_CHECK_EQ(model.extensionNameToPrefix.size(), 1u); // Assumes no other extensions in use. NN_RET_CHECK_EQ(model.extensionNameToPrefix[0].name, EXAMPLE_FIBONACCI_EXTENSION_NAME); *prefix = model.extensionNameToPrefix[0].prefix; return true; } -bool isFibonacciOperation(const Operation& operation, const Model& model) { +bool isFibonacciOperation(const V1_3::Operation& operation, const V1_3::Model& model) { int32_t operationType = static_cast<int32_t>(operation.type); uint16_t prefix; NN_RET_CHECK(getFibonacciExtensionPrefix(model, &prefix)); - NN_RET_CHECK_EQ(operationType, (prefix << kLowBitsType) | EXAMPLE_FIBONACCI); + NN_RET_CHECK_EQ(operationType, (prefix << kExtensionTypeBits) | EXAMPLE_FIBONACCI); return true; } -bool validate(const Operation& operation, const Model& model) { +bool validate(const V1_3::Operation& operation, const V1_3::Model& model) { NN_RET_CHECK(isFibonacciOperation(operation, model)); NN_RET_CHECK_EQ(operation.inputs.size(), kNumInputs); NN_RET_CHECK_EQ(operation.outputs.size(), kNumOutputs); @@ -71,9 +69,9 @@ bool validate(const Operation& operation, const Model& model) { int32_t outputType = static_cast<int32_t>(model.main.operands[operation.outputs[0]].type); uint16_t prefix; NN_RET_CHECK(getFibonacciExtensionPrefix(model, &prefix)); - NN_RET_CHECK(inputType == ((prefix << kLowBitsType) | EXAMPLE_INT64) || + NN_RET_CHECK(inputType == ((prefix << kExtensionTypeBits) | EXAMPLE_INT64) || inputType == ANEURALNETWORKS_TENSOR_FLOAT32); - NN_RET_CHECK(outputType == ((prefix << kLowBitsType) | EXAMPLE_TENSOR_QUANT64_ASYMM) || + NN_RET_CHECK(outputType == ((prefix << kExtensionTypeBits) | EXAMPLE_TENSOR_QUANT64_ASYMM) || outputType == ANEURALNETWORKS_TENSOR_FLOAT32); return true; } @@ -128,7 +126,7 @@ bool execute(IOperationExecutionContext* context) { uint64_t* output = context->getOutputBuffer<uint64_t>(kOutputTensor); Shape outputShape = context->getOutputShape(kOutputTensor); auto outputQuant = reinterpret_cast<const ExampleQuant64AsymmParams*>( - outputShape.extraParams.extension().data()); + std::get<Operand::ExtensionParams>(outputShape.extraParams).data()); return compute(n, outputQuant->scale, outputQuant->zeroPoint, output); } } @@ -142,14 +140,14 @@ const OperationRegistration* FibonacciOperationResolver::findOperation( static OperationRegistration operationRegistration(operationType, fibonacci_op::kOperationName, nullptr, fibonacci_op::prepare, fibonacci_op::execute, {}); - uint16_t prefix = static_cast<int32_t>(operationType) >> kLowBitsType; + uint16_t prefix = static_cast<int32_t>(operationType) >> kExtensionTypeBits; uint16_t typeWithinExtension = static_cast<int32_t>(operationType) & kTypeWithinExtensionMask; // Assumes no other extensions in use. return prefix != 0 && typeWithinExtension == EXAMPLE_FIBONACCI ? &operationRegistration : nullptr; } -Return<void> FibonacciDriver::getSupportedExtensions(getSupportedExtensions_cb cb) { +hardware::Return<void> FibonacciDriver::getSupportedExtensions(getSupportedExtensions_cb cb) { cb(V1_0::ErrorStatus::NONE, { { @@ -169,44 +167,44 @@ Return<void> FibonacciDriver::getSupportedExtensions(getSupportedExtensions_cb c }, }, }); - return Void(); + return hardware::Void(); } -Return<void> FibonacciDriver::getCapabilities_1_3(getCapabilities_1_3_cb cb) { +hardware::Return<void> FibonacciDriver::getCapabilities_1_3(getCapabilities_1_3_cb cb) { android::nn::initVLogMask(); VLOG(DRIVER) << "getCapabilities()"; - static const PerformanceInfo kPerf = {.execTime = 1.0f, .powerUsage = 1.0f}; - Capabilities capabilities = { + static const V1_0::PerformanceInfo kPerf = {.execTime = 1.0f, .powerUsage = 1.0f}; + V1_3::Capabilities capabilities = { .relaxedFloat32toFloat16PerformanceScalar = kPerf, .relaxedFloat32toFloat16PerformanceTensor = kPerf, .operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>(kPerf), .ifPerformance = kPerf, .whilePerformance = kPerf}; cb(V1_3::ErrorStatus::NONE, capabilities); - return Void(); + return hardware::Void(); } -Return<void> FibonacciDriver::getSupportedOperations_1_3(const V1_3::Model& model, - getSupportedOperations_1_3_cb cb) { +hardware::Return<void> FibonacciDriver::getSupportedOperations_1_3( + const V1_3::Model& model, getSupportedOperations_1_3_cb cb) { VLOG(DRIVER) << "getSupportedOperations()"; if (!validateModel(model)) { cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}); - return Void(); + return hardware::Void(); } const size_t count = model.main.operations.size(); std::vector<bool> supported(count); for (size_t i = 0; i < count; ++i) { - const Operation& operation = model.main.operations[i]; + const V1_3::Operation& operation = model.main.operations[i]; if (fibonacci_op::isFibonacciOperation(operation, model)) { if (!fibonacci_op::validate(operation, model)) { cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}); - return Void(); + return hardware::Void(); } supported[i] = true; } } cb(V1_3::ErrorStatus::NONE, supported); - return Void(); + return hardware::Void(); } } // namespace sample_driver diff --git a/nn/runtime/test/fibonacci_extension/FibonacciDriver.h b/nn/runtime/test/fibonacci_extension/FibonacciDriver.h index 303edd809..7daf4d2de 100644 --- a/nn/runtime/test/fibonacci_extension/FibonacciDriver.h +++ b/nn/runtime/test/fibonacci_extension/FibonacciDriver.h @@ -34,7 +34,7 @@ class FibonacciOperationResolver : public IOperationResolver { return &instance; } - const OperationRegistration* findOperation(hal::OperationType operationType) const override; + const OperationRegistration* findOperation(OperationType operationType) const override; private: FibonacciOperationResolver() {} @@ -45,10 +45,10 @@ class FibonacciOperationResolver : public IOperationResolver { class FibonacciDriver : public SampleDriver { public: FibonacciDriver() : SampleDriver(kDriverName, FibonacciOperationResolver::get()) {} - hal::Return<void> getSupportedExtensions(getSupportedExtensions_cb cb) override; - hal::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; - hal::Return<void> getSupportedOperations_1_3(const hal::V1_3::Model& model, - getSupportedOperations_1_3_cb cb) override; + hardware::Return<void> getSupportedExtensions(getSupportedExtensions_cb cb) override; + hardware::Return<void> getCapabilities_1_3(getCapabilities_1_3_cb cb) override; + hardware::Return<void> getSupportedOperations_1_3(const V1_3::Model& model, + getSupportedOperations_1_3_cb cb) override; static constexpr char kDriverName[] = "sample-driver-fibonacci-extension"; }; diff --git a/nn/runtime/test/fuzzing/RandomGraphGenerator.cpp b/nn/runtime/test/fuzzing/RandomGraphGenerator.cpp index 9799ca00c..8ba763aad 100644 --- a/nn/runtime/test/fuzzing/RandomGraphGenerator.cpp +++ b/nn/runtime/test/fuzzing/RandomGraphGenerator.cpp @@ -44,7 +44,7 @@ using namespace test_helper; RandomOperand::RandomOperand(const OperandSignature& operand, TestOperandType dataType, uint32_t rank) : type(operand.type), finalizer(operand.finalizer) { - NN_FUZZER_LOG << "Operand: " << toString(type); + NN_FUZZER_LOG << "Operand: " << type; if (operand.constructor) operand.constructor(dataType, rank, this); } @@ -81,7 +81,7 @@ size_t RandomOperand::getBufferSize() const { // Construct a RandomOperation from OperationSignature. RandomOperation::RandomOperation(const OperationSignature& operation) : opType(operation.opType), finalizer(operation.finalizer) { - NN_FUZZER_LOG << "Operation: " << toString(opType); + NN_FUZZER_LOG << "Operation: " << opType; // Determine the data type and rank of the operation and invoke the constructor. TestOperandType dataType = getRandomChoice(operation.supportedDataTypes); @@ -294,14 +294,14 @@ TestModel RandomGraph::createTestModel() { // Set model operations. for (auto& operation : mOperations) { - NN_FUZZER_LOG << "Operation: " << toString(operation.opType); + NN_FUZZER_LOG << "Operation: " << operation.opType; TestOperation testOperation = {.type = static_cast<TestOperationType>(operation.opType)}; for (auto& op : operation.inputs) { - NN_FUZZER_LOG << toString(*op); + NN_FUZZER_LOG << *op; testOperation.inputs.push_back(op->opIndex); } for (auto& op : operation.outputs) { - NN_FUZZER_LOG << toString(*op); + NN_FUZZER_LOG << *op; testOperation.outputs.push_back(op->opIndex); } testModel.main.operations.push_back(std::move(testOperation)); diff --git a/nn/runtime/test/fuzzing/RandomGraphGeneratorUtils.h b/nn/runtime/test/fuzzing/RandomGraphGeneratorUtils.h index 1aa7fea41..8faae1271 100644 --- a/nn/runtime/test/fuzzing/RandomGraphGeneratorUtils.h +++ b/nn/runtime/test/fuzzing/RandomGraphGeneratorUtils.h @@ -119,18 +119,13 @@ class LoggerStream { }; template <typename T> -inline std::string toString(const T& obj) { - return std::to_string(obj); -} - -template <typename T> inline std::string joinStr(const std::string& joint, const std::vector<T>& items) { std::stringstream ss; for (uint32_t i = 0; i < items.size(); i++) { if (i == 0) { - ss << toString(items[i]); + ss << items[i]; } else { - ss << joint << toString(items[i]); + ss << joint << items[i]; } } return ss.str(); @@ -150,18 +145,15 @@ template <typename T> inline std::string joinStr(const std::string& joint, int limit, const std::vector<T>& items) { if (items.size() > static_cast<size_t>(limit)) { std::vector<T> topMax(items.begin(), items.begin() + limit); - return joinStr(joint, topMax) + ", (" + toString(items.size() - limit) + " ommited), " + - toString(items.back()); + std::stringstream ss; + ss << joinStr(joint, topMax) << ", (" << (items.size() - limit) << " omitted), " + << items.back(); + return ss.str(); } else { return joinStr(joint, items); } } -static const char* kLifeTimeNames[6] = { - "TEMPORARY_VARIABLE", "SUBGRAPH_INPUT", "SUBGRAPH_OUTPUT", - "CONSTANT_COPY", "CONSTANT_REFERENCE", "NO_VALUE", -}; - static const bool kScalarDataType[]{ true, // ANEURALNETWORKS_FLOAT32 true, // ANEURALNETWORKS_INT32 @@ -198,10 +190,9 @@ static const uint32_t kSizeOfDataType[]{ 1, // ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED }; -template <> -inline std::string toString<RandomVariableType>(const RandomVariableType& type) { +inline std::ostream& operator<<(std::ostream& os, const RandomVariableType& type) { static const std::string typeNames[] = {"FREE", "CONST", "OP"}; - return typeNames[static_cast<int>(type)]; + return os << typeNames[static_cast<int>(type)]; } inline std::string alignedString(std::string str, int width) { @@ -210,51 +201,45 @@ inline std::string alignedString(std::string str, int width) { return str; } -template <> -inline std::string toString<RandomVariableRange>(const RandomVariableRange& range) { - return "[" + joinStr(", ", 20, range.getChoices()) + "]"; +inline std::ostream& operator<<(std::ostream& os, const RandomVariableRange& range) { + return os << "[" + joinStr(", ", 20, range.getChoices()) + "]"; } -template <> -inline std::string toString<RandomOperandType>(const RandomOperandType& type) { +inline std::ostream& operator<<(std::ostream& os, const RandomOperandType& type) { static const std::string typeNames[] = {"Input", "Output", "Internal", "Parameter", "No Value"}; - return typeNames[static_cast<int>(type)]; + return os << typeNames[static_cast<int>(type)]; } -template <> -inline std::string toString<RandomVariableNode>(const RandomVariableNode& var) { - std::stringstream ss; - ss << "var" << var->index << " = "; +inline std::ostream& operator<<(std::ostream& os, const RandomVariableNode& var) { + os << "var" << var->index << " = "; switch (var->type) { case RandomVariableType::FREE: - ss << "FREE " << toString(var->range); + os << "FREE " << var->range; break; case RandomVariableType::CONST: - ss << "CONST " << toString(var->value); + os << "CONST " << var->value; break; case RandomVariableType::OP: - ss << "var" << var->parent1->index << " " << var->op->getName(); - if (var->parent2 != nullptr) ss << " var" << var->parent2->index; - ss << ", " << toString(var->range); + os << "var" << var->parent1->index << " " << var->op->getName(); + if (var->parent2 != nullptr) os << " var" << var->parent2->index; + os << ", " << var->range; break; default: NN_FUZZER_CHECK(false); } - ss << ", timestamp = " << var->timestamp; - return ss.str(); + os << ", timestamp = " << var->timestamp; + return os; } -template <> -inline std::string toString<RandomVariable>(const RandomVariable& var) { - return "var" + std::to_string(var.get()->index); +inline std::ostream& operator<<(std::ostream& os, const RandomVariable& var) { + return os << "var" + std::to_string(var.get()->index); } -template <> -inline std::string toString<RandomOperand>(const RandomOperand& op) { - return toString(op.type) + ", dimension = [" + - joinStr(", ", op.dimensions, - [](const RandomVariable& var) { return std::to_string(var.getValue()); }) + - "], scale = " + toString(op.scale) + " , zero_point = " + toString(op.zeroPoint); +inline std::ostream& operator<<(std::ostream& os, const RandomOperand& op) { + return os << op.type << ", dimension = [" + << joinStr(", ", op.dimensions, + [](const RandomVariable& var) { return std::to_string(var.getValue()); }) + << "], scale = " << op.scale << " , zero_point = " << op.zeroPoint; } // This class is a workaround for two issues our code relies on: diff --git a/nn/runtime/test/fuzzing/RandomVariable.cpp b/nn/runtime/test/fuzzing/RandomVariable.cpp index d3f6ef7e2..f1067e184 100644 --- a/nn/runtime/test/fuzzing/RandomVariable.cpp +++ b/nn/runtime/test/fuzzing/RandomVariable.cpp @@ -1,1225 +1,1225 @@ -/*
- * Copyright (C) 2019 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 "RandomVariable.h"
-
-#include <algorithm>
-#include <memory>
-#include <set>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include "RandomGraphGeneratorUtils.h"
-
-namespace android {
-namespace nn {
-namespace fuzzing_test {
-
-unsigned int RandomVariableBase::globalIndex = 0;
-int RandomVariable::defaultValue = 10;
-
-RandomVariableBase::RandomVariableBase(int value)
- : index(globalIndex++),
- type(RandomVariableType::CONST),
- range(value),
- value(value),
- timestamp(RandomVariableNetwork::get()->getGlobalTime()) {}
-
-RandomVariableBase::RandomVariableBase(int lower, int upper)
- : index(globalIndex++),
- type(RandomVariableType::FREE),
- range(lower, upper),
- timestamp(RandomVariableNetwork::get()->getGlobalTime()) {}
-
-RandomVariableBase::RandomVariableBase(const std::vector<int>& choices)
- : index(globalIndex++),
- type(RandomVariableType::FREE),
- range(choices),
- timestamp(RandomVariableNetwork::get()->getGlobalTime()) {}
-
-RandomVariableBase::RandomVariableBase(const RandomVariableNode& lhs, const RandomVariableNode& rhs,
- const std::shared_ptr<const IRandomVariableOp>& op)
- : index(globalIndex++),
- type(RandomVariableType::OP),
- range(op->getInitRange(lhs->range, rhs == nullptr ? RandomVariableRange(0) : rhs->range)),
- op(op),
- parent1(lhs),
- parent2(rhs),
- timestamp(RandomVariableNetwork::get()->getGlobalTime()) {}
-
-void RandomVariableRange::setRange(int lower, int upper) {
- // kInvalidValue indicates unlimited bound.
- auto head = lower == kInvalidValue ? mChoices.begin()
- : std::lower_bound(mChoices.begin(), mChoices.end(), lower);
- auto tail = upper == kInvalidValue ? mChoices.end()
- : std::upper_bound(mChoices.begin(), mChoices.end(), upper);
- NN_FUZZER_CHECK(head <= tail) << "Invalid range!";
- if (head != mChoices.begin() || tail != mChoices.end()) {
- mChoices = std::vector<int>(head, tail);
- }
-}
-
-int RandomVariableRange::toConst() {
- if (mChoices.size() > 1) mChoices = {getRandomChoice(mChoices)};
- return mChoices[0];
-}
-
-RandomVariableRange operator&(const RandomVariableRange& lhs, const RandomVariableRange& rhs) {
- std::vector<int> result(lhs.size() + rhs.size());
- auto it = std::set_intersection(lhs.mChoices.begin(), lhs.mChoices.end(), rhs.mChoices.begin(),
- rhs.mChoices.end(), result.begin());
- result.resize(it - result.begin());
- return RandomVariableRange(std::move(result));
-}
-
-void RandomVariableBase::freeze() {
- if (type == RandomVariableType::CONST) return;
- value = range.toConst();
- type = RandomVariableType::CONST;
-}
-
-int RandomVariableBase::getValue() const {
- switch (type) {
- case RandomVariableType::CONST:
- return value;
- case RandomVariableType::OP:
- return op->eval(parent1->getValue(), parent2 == nullptr ? 0 : parent2->getValue());
- default:
- NN_FUZZER_CHECK(false) << "Invalid type when getting value of var" << index;
- return 0;
- }
-}
-
-void RandomVariableBase::updateTimestamp() {
- timestamp = RandomVariableNetwork::get()->getGlobalTime();
- NN_FUZZER_LOG << "Update timestamp of var" << index << " to " << timestamp;
-}
-
-RandomVariable::RandomVariable(int value) : mVar(new RandomVariableBase(value)) {
- NN_FUZZER_LOG << "New RandomVariable " << toString(mVar);
- RandomVariableNetwork::get()->add(mVar);
-}
-RandomVariable::RandomVariable(int lower, int upper) : mVar(new RandomVariableBase(lower, upper)) {
- NN_FUZZER_LOG << "New RandomVariable " << toString(mVar);
- RandomVariableNetwork::get()->add(mVar);
-}
-RandomVariable::RandomVariable(const std::vector<int>& choices)
- : mVar(new RandomVariableBase(choices)) {
- NN_FUZZER_LOG << "New RandomVariable " << toString(mVar);
- RandomVariableNetwork::get()->add(mVar);
-}
-RandomVariable::RandomVariable(RandomVariableType type)
- : mVar(new RandomVariableBase(1, defaultValue)) {
- NN_FUZZER_CHECK(type == RandomVariableType::FREE);
- NN_FUZZER_LOG << "New RandomVariable " << toString(mVar);
- RandomVariableNetwork::get()->add(mVar);
-}
-RandomVariable::RandomVariable(const RandomVariable& lhs, const RandomVariable& rhs,
- const std::shared_ptr<const IRandomVariableOp>& op)
- : mVar(new RandomVariableBase(lhs.get(), rhs.get(), op)) {
- // Make a copy if the parent is CONST. This will resolve the fake dependency problem.
- if (mVar->parent1->type == RandomVariableType::CONST) {
- mVar->parent1 = RandomVariable(mVar->parent1->value).get();
- }
- if (mVar->parent2 != nullptr && mVar->parent2->type == RandomVariableType::CONST) {
- mVar->parent2 = RandomVariable(mVar->parent2->value).get();
- }
- mVar->parent1->children.push_back(mVar);
- if (mVar->parent2 != nullptr) mVar->parent2->children.push_back(mVar);
- RandomVariableNetwork::get()->add(mVar);
- NN_FUZZER_LOG << "New RandomVariable " << toString(mVar);
-}
-
-void RandomVariable::setRange(int lower, int upper) {
- NN_FUZZER_CHECK(mVar != nullptr) << "setRange() on nullptr";
- NN_FUZZER_LOG << "Set range [" << lower << ", " << upper << "] on var" << mVar->index;
- size_t oldSize = mVar->range.size();
- mVar->range.setRange(lower, upper);
- // Only update the timestamp if the range is *indeed* narrowed down.
- if (mVar->range.size() != oldSize) mVar->updateTimestamp();
-}
-
-RandomVariableRange IRandomVariableOp::getInitRange(const RandomVariableRange& lhs,
- const RandomVariableRange& rhs) const {
- std::set<int> st;
- for (auto i : lhs.getChoices()) {
- for (auto j : rhs.getChoices()) {
- int res = this->eval(i, j);
- if (res > kMaxValue || res < -kMaxValue) continue;
- st.insert(res);
- }
- }
- return RandomVariableRange(st);
-}
-
-// Check if the range contains exactly all values in [min, max].
-static inline bool isContinuous(const std::set<int>* range) {
- return (*(range->rbegin()) - *(range->begin()) + 1) == static_cast<int>(range->size());
-}
-
-// Fill the set with a range of values specified by [lower, upper].
-static inline void fillRange(std::set<int>* range, int lower, int upper) {
- for (int i = lower; i <= upper; i++) range->insert(i);
-}
-
-// The slowest algorithm: iterate through every combinations of parents and save the valid pairs.
-void IRandomVariableOp::eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>* childIn, std::set<int>* parent1Out,
- std::set<int>* parent2Out, std::set<int>* childOut) const {
- // Avoid the binary search if the child is a closed range.
- bool isChildInContinuous = isContinuous(childIn);
- std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()};
- for (auto i : *parent1In) {
- bool valid = false;
- for (auto j : *parent2In) {
- int res = this->eval(i, j);
- // Avoid the binary search if obviously out of range.
- if (res > child.second || res < child.first) continue;
- if (isChildInContinuous || childIn->find(res) != childIn->end()) {
- parent2Out->insert(j);
- childOut->insert(res);
- valid = true;
- }
- }
- if (valid) parent1Out->insert(i);
- }
-}
-
-// A helper template to make a class into a Singleton.
-template <class T>
-class Singleton : public T {
- public:
- static const std::shared_ptr<const T>& get() {
- static std::shared_ptr<const T> instance(new T);
- return instance;
- }
-};
-
-// A set of operations that only compute on a single input value.
-class IUnaryOp : public IRandomVariableOp {
- public:
- using IRandomVariableOp::eval;
- virtual int eval(int val) const = 0;
- virtual int eval(int lhs, int) const override { return eval(lhs); }
- // The slowest algorithm: iterate through every value of the parent and save the valid one.
- virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>* childIn, std::set<int>* parent1Out,
- std::set<int>* parent2Out, std::set<int>* childOut) const override {
- NN_FUZZER_CHECK(parent2In == nullptr);
- NN_FUZZER_CHECK(parent2Out == nullptr);
- bool isChildInContinuous = isContinuous(childIn);
- std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()};
- for (auto i : *parent1In) {
- int res = this->eval(i);
- if (res > child.second || res < child.first) continue;
- if (isChildInContinuous || childIn->find(res) != childIn->end()) {
- parent1Out->insert(i);
- childOut->insert(res);
- }
- }
- }
-};
-
-// A set of operations that only check conditional constraints.
-class IConstraintOp : public IRandomVariableOp {
- public:
- using IRandomVariableOp::eval;
- virtual bool check(int lhs, int rhs) const = 0;
- virtual int eval(int lhs, int rhs) const override {
- return check(lhs, rhs) ? 0 : kInvalidValue;
- }
- // The range for a constraint op is always {0}.
- virtual RandomVariableRange getInitRange(const RandomVariableRange&,
- const RandomVariableRange&) const override {
- return RandomVariableRange(0);
- }
- // The slowest algorithm:
- // iterate through every combinations of parents and save the valid pairs.
- virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>*, std::set<int>* parent1Out, std::set<int>* parent2Out,
- std::set<int>* childOut) const override {
- for (auto i : *parent1In) {
- bool valid = false;
- for (auto j : *parent2In) {
- if (this->check(i, j)) {
- parent2Out->insert(j);
- valid = true;
- }
- }
- if (valid) parent1Out->insert(i);
- }
- if (!parent1Out->empty()) childOut->insert(0);
- }
-};
-
-class Addition : public IRandomVariableOp {
- public:
- virtual int eval(int lhs, int rhs) const override { return lhs + rhs; }
- virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs,
- const RandomVariableRange& rhs) const override {
- return RandomVariableRange(lhs.min() + rhs.min(), lhs.max() + rhs.max());
- }
- virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>* childIn, std::set<int>* parent1Out,
- std::set<int>* parent2Out, std::set<int>* childOut) const override {
- if (!isContinuous(parent1In) || !isContinuous(parent2In) || !isContinuous(childIn)) {
- IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out,
- childOut);
- } else {
- // For parents and child with close range, the out range can be computed directly
- // without iterations.
- std::pair<int, int> parent1 = {*parent1In->begin(), *parent1In->rbegin()};
- std::pair<int, int> parent2 = {*parent2In->begin(), *parent2In->rbegin()};
- std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()};
-
- // From ranges for parent, evalute range for child.
- // [a, b] + [c, d] -> [a + c, b + d]
- fillRange(childOut, std::max(child.first, parent1.first + parent2.first),
- std::min(child.second, parent1.second + parent2.second));
-
- // From ranges for child and one parent, evalute range for another parent.
- // [a, b] - [c, d] -> [a - d, b - c]
- fillRange(parent1Out, std::max(parent1.first, child.first - parent2.second),
- std::min(parent1.second, child.second - parent2.first));
- fillRange(parent2Out, std::max(parent2.first, child.first - parent1.second),
- std::min(parent2.second, child.second - parent1.first));
- }
- }
- virtual const char* getName() const override { return "ADD"; }
-};
-
-class Subtraction : public IRandomVariableOp {
- public:
- virtual int eval(int lhs, int rhs) const override { return lhs - rhs; }
- virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs,
- const RandomVariableRange& rhs) const override {
- return RandomVariableRange(lhs.min() - rhs.max(), lhs.max() - rhs.min());
- }
- virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>* childIn, std::set<int>* parent1Out,
- std::set<int>* parent2Out, std::set<int>* childOut) const override {
- if (!isContinuous(parent1In) || !isContinuous(parent2In) || !isContinuous(childIn)) {
- IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out,
- childOut);
- } else {
- // Similar algorithm as Addition.
- std::pair<int, int> parent1 = {*parent1In->begin(), *parent1In->rbegin()};
- std::pair<int, int> parent2 = {*parent2In->begin(), *parent2In->rbegin()};
- std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()};
- fillRange(childOut, std::max(child.first, parent1.first - parent2.second),
- std::min(child.second, parent1.second - parent2.first));
- fillRange(parent1Out, std::max(parent1.first, child.first + parent2.first),
- std::min(parent1.second, child.second + parent2.second));
- fillRange(parent2Out, std::max(parent2.first, parent1.first - child.second),
- std::min(parent2.second, parent1.second - child.first));
- }
- }
- virtual const char* getName() const override { return "SUB"; }
-};
-
-class Multiplication : public IRandomVariableOp {
- public:
- virtual int eval(int lhs, int rhs) const override { return lhs * rhs; }
- virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs,
- const RandomVariableRange& rhs) const override {
- if (lhs.min() < 0 || rhs.min() < 0) {
- return IRandomVariableOp::getInitRange(lhs, rhs);
- } else {
- int lower = std::min(lhs.min() * rhs.min(), kMaxValue);
- int upper = std::min(lhs.max() * rhs.max(), kMaxValue);
- return RandomVariableRange(lower, upper);
- }
- }
- virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>* childIn, std::set<int>* parent1Out,
- std::set<int>* parent2Out, std::set<int>* childOut) const override {
- if (*parent1In->begin() < 0 || *parent2In->begin() < 0 || *childIn->begin() < 0) {
- IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out,
- childOut);
- } else {
- bool isChildInContinuous = isContinuous(childIn);
- std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()};
- for (auto i : *parent1In) {
- bool valid = false;
- for (auto j : *parent2In) {
- int res = this->eval(i, j);
- // Since MUL increases monotonically with one value, break the loop if the
- // result is larger than the limit.
- if (res > child.second) break;
- if (res < child.first) continue;
- if (isChildInContinuous || childIn->find(res) != childIn->end()) {
- valid = true;
- parent2Out->insert(j);
- childOut->insert(res);
- }
- }
- if (valid) parent1Out->insert(i);
- }
- }
- }
- virtual const char* getName() const override { return "MUL"; }
-};
-
-class Division : public IRandomVariableOp {
- public:
- virtual int eval(int lhs, int rhs) const override {
- return rhs == 0 ? kInvalidValue : lhs / rhs;
- }
- virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs,
- const RandomVariableRange& rhs) const override {
- if (lhs.min() < 0 || rhs.min() <= 0) {
- return IRandomVariableOp::getInitRange(lhs, rhs);
- } else {
- return RandomVariableRange(lhs.min() / rhs.max(), lhs.max() / rhs.min());
- }
- }
- virtual const char* getName() const override { return "DIV"; }
-};
-
-class ExactDivision : public Division {
- public:
- virtual int eval(int lhs, int rhs) const override {
- return (rhs == 0 || lhs % rhs != 0) ? kInvalidValue : lhs / rhs;
- }
- virtual const char* getName() const override { return "EXACT_DIV"; }
-};
-
-class Modulo : public IRandomVariableOp {
- public:
- virtual int eval(int lhs, int rhs) const override {
- return rhs == 0 ? kInvalidValue : lhs % rhs;
- }
- virtual RandomVariableRange getInitRange(const RandomVariableRange&,
- const RandomVariableRange& rhs) const override {
- return RandomVariableRange(0, rhs.max());
- }
- virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>* childIn, std::set<int>* parent1Out,
- std::set<int>* parent2Out, std::set<int>* childOut) const override {
- if (*childIn->begin() != 0 || childIn->size() != 1u) {
- IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out,
- childOut);
- } else {
- // For the special case that child is a const 0, it would be faster if the range for
- // parents are evaluated separately.
-
- // Evalute parent1 directly.
- for (auto i : *parent1In) {
- for (auto j : *parent2In) {
- if (i % j == 0) {
- parent1Out->insert(i);
- break;
- }
- }
- }
- // Evalute parent2, see if a multiple of parent2 value can be found in parent1.
- int parent1Max = *parent1In->rbegin();
- for (auto i : *parent2In) {
- int jMax = parent1Max / i;
- for (int j = 1; j <= jMax; j++) {
- if (parent1In->find(i * j) != parent1In->end()) {
- parent2Out->insert(i);
- break;
- }
- }
- }
- if (!parent1Out->empty()) childOut->insert(0);
- }
- }
- virtual const char* getName() const override { return "MOD"; }
-};
-
-class Maximum : public IRandomVariableOp {
- public:
- virtual int eval(int lhs, int rhs) const override { return std::max(lhs, rhs); }
- virtual const char* getName() const override { return "MAX"; }
-};
-
-class Minimum : public IRandomVariableOp {
- public:
- virtual int eval(int lhs, int rhs) const override { return std::min(lhs, rhs); }
- virtual const char* getName() const override { return "MIN"; }
-};
-
-class Square : public IUnaryOp {
- public:
- virtual int eval(int val) const override { return val * val; }
- virtual const char* getName() const override { return "SQUARE"; }
-};
-
-class UnaryEqual : public IUnaryOp {
- public:
- virtual int eval(int val) const override { return val; }
- virtual const char* getName() const override { return "UNARY_EQUAL"; }
-};
-
-class Equal : public IConstraintOp {
- public:
- virtual bool check(int lhs, int rhs) const override { return lhs == rhs; }
- virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In,
- const std::set<int>* childIn, std::set<int>* parent1Out,
- std::set<int>* parent2Out, std::set<int>* childOut) const override {
- NN_FUZZER_CHECK(childIn->size() == 1u && *childIn->begin() == 0);
- // The intersection of two sets can be found in O(n).
- std::set_intersection(parent1In->begin(), parent1In->end(), parent2In->begin(),
- parent2In->end(), std::inserter(*parent1Out, parent1Out->begin()));
- *parent2Out = *parent1Out;
- childOut->insert(0);
- }
- virtual const char* getName() const override { return "EQUAL"; }
-};
-
-class GreaterThan : public IConstraintOp {
- public:
- virtual bool check(int lhs, int rhs) const override { return lhs > rhs; }
- virtual const char* getName() const override { return "GREATER_THAN"; }
-};
-
-class GreaterEqual : public IConstraintOp {
- public:
- virtual bool check(int lhs, int rhs) const override { return lhs >= rhs; }
- virtual const char* getName() const override { return "GREATER_EQUAL"; }
-};
-
-class FloatMultiplication : public IUnaryOp {
- public:
- FloatMultiplication(float multiplicand) : mMultiplicand(multiplicand) {}
- virtual int eval(int val) const override {
- return static_cast<int>(std::floor(static_cast<float>(val) * mMultiplicand));
- }
- virtual const char* getName() const override { return "MUL_FLOAT"; }
-
- private:
- float mMultiplicand;
-};
-
-// Arithmetic operators and methods on RandomVariables will create OP RandomVariableNodes.
-// Since there must be at most one edge between two RandomVariableNodes, we have to do something
-// special when both sides are refering to the same node.
-
-RandomVariable operator+(const RandomVariable& lhs, const RandomVariable& rhs) {
- return lhs.get() == rhs.get() ? RandomVariable(lhs, 2, Singleton<Multiplication>::get())
- : RandomVariable(lhs, rhs, Singleton<Addition>::get());
-}
-RandomVariable operator-(const RandomVariable& lhs, const RandomVariable& rhs) {
- return lhs.get() == rhs.get() ? RandomVariable(0)
- : RandomVariable(lhs, rhs, Singleton<Subtraction>::get());
-}
-RandomVariable operator*(const RandomVariable& lhs, const RandomVariable& rhs) {
- return lhs.get() == rhs.get() ? RandomVariable(lhs, RandomVariable(), Singleton<Square>::get())
- : RandomVariable(lhs, rhs, Singleton<Multiplication>::get());
-}
-RandomVariable operator*(const RandomVariable& lhs, const float& rhs) {
- return RandomVariable(lhs, RandomVariable(), std::make_shared<FloatMultiplication>(rhs));
-}
-RandomVariable operator/(const RandomVariable& lhs, const RandomVariable& rhs) {
- return lhs.get() == rhs.get() ? RandomVariable(1)
- : RandomVariable(lhs, rhs, Singleton<Division>::get());
-}
-RandomVariable operator%(const RandomVariable& lhs, const RandomVariable& rhs) {
- return lhs.get() == rhs.get() ? RandomVariable(0)
- : RandomVariable(lhs, rhs, Singleton<Modulo>::get());
-}
-RandomVariable max(const RandomVariable& lhs, const RandomVariable& rhs) {
- return lhs.get() == rhs.get() ? lhs : RandomVariable(lhs, rhs, Singleton<Maximum>::get());
-}
-RandomVariable min(const RandomVariable& lhs, const RandomVariable& rhs) {
- return lhs.get() == rhs.get() ? lhs : RandomVariable(lhs, rhs, Singleton<Minimum>::get());
-}
-
-RandomVariable RandomVariable::exactDiv(const RandomVariable& other) {
- return mVar == other.get() ? RandomVariable(1)
- : RandomVariable(*this, other, Singleton<ExactDivision>::get());
-}
-
-RandomVariable RandomVariable::setEqual(const RandomVariable& other) const {
- RandomVariableNode node1 = mVar, node2 = other.get();
- NN_FUZZER_LOG << "Set equality of var" << node1->index << " and var" << node2->index;
-
- // Do not setEqual on the same pair twice.
- if (node1 == node2 || (node1->op == Singleton<UnaryEqual>::get() && node1->parent1 == node2) ||
- (node2->op == Singleton<UnaryEqual>::get() && node2->parent1 == node1)) {
- NN_FUZZER_LOG << "Already equal. Return.";
- return RandomVariable();
- }
-
- // If possible, always try UnaryEqual first to reduce the search space.
- // UnaryEqual can be used if node B is FREE and is evaluated later than node A.
- // TODO: Reduce code duplication.
- if (RandomVariableNetwork::get()->isSubordinate(node1, node2)) {
- NN_FUZZER_LOG << " Make var" << node2->index << " a child of var" << node1->index;
- node2->type = RandomVariableType::OP;
- node2->parent1 = node1;
- node2->op = Singleton<UnaryEqual>::get();
- node1->children.push_back(node2);
- RandomVariableNetwork::get()->join(node1, node2);
- node1->updateTimestamp();
- return other;
- }
- if (RandomVariableNetwork::get()->isSubordinate(node2, node1)) {
- NN_FUZZER_LOG << " Make var" << node1->index << " a child of var" << node2->index;
- node1->type = RandomVariableType::OP;
- node1->parent1 = node2;
- node1->op = Singleton<UnaryEqual>::get();
- node2->children.push_back(node1);
- RandomVariableNetwork::get()->join(node2, node1);
- node1->updateTimestamp();
- return *this;
- }
- return RandomVariable(*this, other, Singleton<Equal>::get());
-}
-
-RandomVariable RandomVariable::setGreaterThan(const RandomVariable& other) const {
- NN_FUZZER_CHECK(mVar != other.get());
- return RandomVariable(*this, other, Singleton<GreaterThan>::get());
-}
-RandomVariable RandomVariable::setGreaterEqual(const RandomVariable& other) const {
- return mVar == other.get() ? *this
- : RandomVariable(*this, other, Singleton<GreaterEqual>::get());
-}
-
-void DisjointNetwork::add(const RandomVariableNode& var) {
- // Find the subnet index of the parents and decide the index for var.
- int ind1 = var->parent1 == nullptr ? -1 : mIndexMap[var->parent1];
- int ind2 = var->parent2 == nullptr ? -1 : mIndexMap[var->parent2];
- int ind = join(ind1, ind2);
- // If no parent, put it into a new subnet component.
- if (ind == -1) ind = mNextIndex++;
- NN_FUZZER_LOG << "Add RandomVariable var" << var->index << " to network #" << ind;
- mIndexMap[var] = ind;
- mEvalOrderMap[ind].push_back(var);
-}
-
-int DisjointNetwork::join(int ind1, int ind2) {
- if (ind1 == -1) return ind2;
- if (ind2 == -1) return ind1;
- if (ind1 == ind2) return ind1;
- NN_FUZZER_LOG << "Join network #" << ind1 << " and #" << ind2;
- auto &order1 = mEvalOrderMap[ind1], &order2 = mEvalOrderMap[ind2];
- // Append every node in ind2 to the end of ind1
- for (const auto& var : order2) {
- order1.push_back(var);
- mIndexMap[var] = ind1;
- }
- // Remove ind2 from mEvalOrderMap.
- mEvalOrderMap.erase(mEvalOrderMap.find(ind2));
- return ind1;
-}
-
-RandomVariableNetwork* RandomVariableNetwork::get() {
- static RandomVariableNetwork instance;
- return &instance;
-}
-
-void RandomVariableNetwork::initialize(int defaultValue) {
- RandomVariableBase::globalIndex = 0;
- RandomVariable::defaultValue = defaultValue;
- mIndexMap.clear();
- mEvalOrderMap.clear();
- mDimProd.clear();
- mNextIndex = 0;
- mGlobalTime = 0;
- mTimestamp = -1;
-}
-
-bool RandomVariableNetwork::isSubordinate(const RandomVariableNode& node1,
- const RandomVariableNode& node2) {
- if (node2->type != RandomVariableType::FREE) return false;
- int ind1 = mIndexMap[node1];
- // node2 is of a different subnet.
- if (ind1 != mIndexMap[node2]) return true;
- for (const auto& node : mEvalOrderMap[ind1]) {
- if (node == node2) return false;
- // node2 is of the same subnet but evaluated later than node1.
- if (node == node1) return true;
- }
- NN_FUZZER_CHECK(false) << "Code executed in non-reachable region.";
- return false;
-}
-
-struct EvalInfo {
- // The RandomVariableNode that this EvalInfo is associated with.
- // var->value is the current value during evaluation.
- RandomVariableNode var;
-
- // The RandomVariable value is staged when a valid combination is found.
- std::set<int> staging;
-
- // The staging values are committed after a subnet evaluation.
- std::set<int> committed;
-
- // Keeps track of the latest timestamp that committed is updated.
- int timestamp;
-
- // For evalSubnetWithLocalNetwork.
- RandomVariableType originalType;
-
- // Should only invoke eval on OP RandomVariable.
- bool eval() {
- NN_FUZZER_CHECK(var->type == RandomVariableType::OP);
- var->value = var->op->eval(var->parent1->value,
- var->parent2 == nullptr ? 0 : var->parent2->value);
- if (var->value == kInvalidValue) return false;
- return committed.find(var->value) != committed.end();
- }
- void stage() { staging.insert(var->value); }
- void commit() {
- // Only update committed and timestamp if the range is *indeed* changed.
- if (staging.size() != committed.size()) {
- committed = std::move(staging);
- timestamp = RandomVariableNetwork::get()->getGlobalTime();
- }
- staging.clear();
- }
- void updateRange() {
- // Only update range and timestamp if the range is *indeed* changed.
- if (committed.size() != var->range.size()) {
- var->range = RandomVariableRange(committed);
- var->timestamp = timestamp;
- }
- committed.clear();
- }
-
- EvalInfo(const RandomVariableNode& var)
- : var(var),
- committed(var->range.getChoices().begin(), var->range.getChoices().end()),
- timestamp(var->timestamp) {}
-};
-using EvalContext = std::unordered_map<RandomVariableNode, EvalInfo>;
-
-// For logging only.
-inline std::string toString(const RandomVariableNode& var, EvalContext* context) {
- std::stringstream ss;
- ss << "var" << var->index << " = ";
- const auto& committed = context->at(var).committed;
- switch (var->type) {
- case RandomVariableType::FREE:
- ss << "FREE ["
- << joinStr(", ", 20, std::vector<int>(committed.begin(), committed.end())) << "]";
- break;
- case RandomVariableType::CONST:
- ss << "CONST " << toString(var->value);
- break;
- case RandomVariableType::OP:
- ss << "var" << var->parent1->index << " " << var->op->getName();
- if (var->parent2 != nullptr) ss << " var" << var->parent2->index;
- ss << ", [" << joinStr(", ", 20, std::vector<int>(committed.begin(), committed.end()))
- << "]";
- break;
- default:
- NN_FUZZER_CHECK(false);
- }
- ss << ", timestamp = " << context->at(var).timestamp;
- return ss.str();
-}
-
-// Check if the subnet needs to be re-evaluated by comparing the timestamps.
-static inline bool needEvaluate(const EvaluationOrder& evalOrder, int subnetTime,
- EvalContext* context = nullptr) {
- for (const auto& var : evalOrder) {
- int timestamp = context == nullptr ? var->timestamp : context->at(var).timestamp;
- // If we find a node that has been modified since last evaluation, the subnet needs to be
- // re-evaluated.
- if (timestamp > subnetTime) return true;
- }
- return false;
-}
-
-// Helper function to evaluate the subnet recursively.
-// Iterate through all combinations of FREE RandomVariables choices.
-static void evalSubnetHelper(const EvaluationOrder& evalOrder, EvalContext* context, size_t i = 0) {
- if (i == evalOrder.size()) {
- // Reach the end of the evaluation, find a valid combination.
- for (auto& var : evalOrder) context->at(var).stage();
- return;
- }
- const auto& var = evalOrder[i];
- if (var->type == RandomVariableType::FREE) {
- // For FREE RandomVariable, iterate through all valid choices.
- for (int val : context->at(var).committed) {
- var->value = val;
- evalSubnetHelper(evalOrder, context, i + 1);
- }
- return;
- } else if (var->type == RandomVariableType::OP) {
- // For OP RandomVariable, evaluate from parents and terminate if the result is invalid.
- if (!context->at(var).eval()) return;
- }
- evalSubnetHelper(evalOrder, context, i + 1);
-}
-
-// Check if the subnet has only one single OP RandomVariable.
-static inline bool isSingleOpSubnet(const EvaluationOrder& evalOrder) {
- int numOp = 0;
- for (const auto& var : evalOrder) {
- if (var->type == RandomVariableType::OP) numOp++;
- if (numOp > 1) return false;
- }
- return numOp != 0;
-}
-
-// Evaluate with a potentially faster approach provided by IRandomVariableOp.
-static inline void evalSubnetSingleOpHelper(const EvaluationOrder& evalOrder,
- EvalContext* context) {
- NN_FUZZER_LOG << "Identified as single op subnet";
- const auto& var = evalOrder.back();
- NN_FUZZER_CHECK(var->type == RandomVariableType::OP);
- var->op->eval(&context->at(var->parent1).committed,
- var->parent2 == nullptr ? nullptr : &context->at(var->parent2).committed,
- &context->at(var).committed, &context->at(var->parent1).staging,
- var->parent2 == nullptr ? nullptr : &context->at(var->parent2).staging,
- &context->at(var).staging);
-}
-
-// Check if the number of combinations of FREE RandomVariables exceeds the limit.
-static inline uint64_t getNumCombinations(const EvaluationOrder& evalOrder,
- EvalContext* context = nullptr) {
- constexpr uint64_t kLimit = 1e8;
- uint64_t numCombinations = 1;
- for (const auto& var : evalOrder) {
- if (var->type == RandomVariableType::FREE) {
- size_t size =
- context == nullptr ? var->range.size() : context->at(var).committed.size();
- numCombinations *= size;
- // To prevent overflow.
- if (numCombinations > kLimit) return kLimit;
- }
- }
- return numCombinations;
-}
-
-// Evaluate the subnet recursively. Will return fail if the number of combinations of FREE
-// RandomVariable exceeds the threshold kMaxNumCombinations.
-static bool evalSubnetWithBruteForce(const EvaluationOrder& evalOrder, EvalContext* context) {
- constexpr uint64_t kMaxNumCombinations = 1e7;
- NN_FUZZER_LOG << "Evaluate with brute force";
- if (isSingleOpSubnet(evalOrder)) {
- // If the network only have one single OP, dispatch to a faster evaluation.
- evalSubnetSingleOpHelper(evalOrder, context);
- } else {
- if (getNumCombinations(evalOrder, context) > kMaxNumCombinations) {
- NN_FUZZER_LOG << "Terminate the evaluation because of large search range";
- std::cout << "[ ] Terminate the evaluation because of large search range"
- << std::endl;
- return false;
- }
- evalSubnetHelper(evalOrder, context);
- }
- for (auto& var : evalOrder) {
- if (context->at(var).staging.empty()) {
- NN_FUZZER_LOG << "Evaluation failed at " << toString(var, context);
- return false;
- }
- context->at(var).commit();
- }
- return true;
-}
-
-struct LocalNetwork {
- EvaluationOrder evalOrder;
- std::vector<RandomVariableNode> bridgeNodes;
- int timestamp = 0;
-
- bool eval(EvalContext* context) {
- NN_FUZZER_LOG << "Evaluate local network with timestamp = " << timestamp;
- // Temporarily treat bridge nodes as FREE RandomVariables.
- for (const auto& var : bridgeNodes) {
- context->at(var).originalType = var->type;
- var->type = RandomVariableType::FREE;
- }
- for (const auto& var : evalOrder) {
- context->at(var).staging.clear();
- NN_FUZZER_LOG << " - " << toString(var, context);
- }
- bool success = evalSubnetWithBruteForce(evalOrder, context);
- // Reset the RandomVariable types for bridge nodes.
- for (const auto& var : bridgeNodes) var->type = context->at(var).originalType;
- return success;
- }
-};
-
-// Partition the network further into LocalNetworks based on the result from bridge annotation
-// algorithm.
-class GraphPartitioner : public DisjointNetwork {
- public:
- GraphPartitioner() = default;
-
- std::vector<LocalNetwork> partition(const EvaluationOrder& evalOrder, int timestamp) {
- annotateBridge(evalOrder);
- for (const auto& var : evalOrder) add(var);
- return get(timestamp);
- }
-
- private:
- GraphPartitioner(const GraphPartitioner&) = delete;
- GraphPartitioner& operator=(const GraphPartitioner&) = delete;
-
- // Find the parent-child relationship between var1 and var2, and reset the bridge.
- void setBridgeFlag(const RandomVariableNode& var1, const RandomVariableNode& var2) {
- if (var1->parent1 == var2) {
- mBridgeInfo[var1].isParent1Bridge = true;
- } else if (var1->parent2 == var2) {
- mBridgeInfo[var1].isParent2Bridge = true;
- } else {
- setBridgeFlag(var2, var1);
- }
- }
-
- // Annoate the bridges with DFS -- an edge [u, v] is a bridge if none of u's ancestor is
- // reachable from a node in the subtree of b. The complexity is O(V + E).
- // discoveryTime: The timestamp a node is visited
- // lowTime: The min discovery time of all reachable nodes from the subtree of the node.
- void annotateBridgeHelper(const RandomVariableNode& var, int* time) {
- mBridgeInfo[var].visited = true;
- mBridgeInfo[var].discoveryTime = mBridgeInfo[var].lowTime = (*time)++;
-
- // The algorithm operates on undirected graph. First find all adjacent nodes.
- auto adj = var->children;
- if (var->parent1 != nullptr) adj.push_back(var->parent1);
- if (var->parent2 != nullptr) adj.push_back(var->parent2);
-
- for (const auto& weakChild : adj) {
- auto child = weakChild.lock();
- NN_FUZZER_CHECK(child != nullptr);
- if (mBridgeInfo.find(child) == mBridgeInfo.end()) continue;
- if (!mBridgeInfo[child].visited) {
- mBridgeInfo[child].parent = var;
- annotateBridgeHelper(child, time);
-
- // If none of nodes in the subtree of child is connected to any ancestors of var,
- // then it is a bridge.
- mBridgeInfo[var].lowTime =
- std::min(mBridgeInfo[var].lowTime, mBridgeInfo[child].lowTime);
- if (mBridgeInfo[child].lowTime > mBridgeInfo[var].discoveryTime)
- setBridgeFlag(var, child);
- } else if (mBridgeInfo[var].parent != child) {
- mBridgeInfo[var].lowTime =
- std::min(mBridgeInfo[var].lowTime, mBridgeInfo[child].discoveryTime);
- }
- }
- }
-
- // Find all bridges in the subnet with DFS.
- void annotateBridge(const EvaluationOrder& evalOrder) {
- for (const auto& var : evalOrder) mBridgeInfo[var];
- int time = 0;
- for (const auto& var : evalOrder) {
- if (!mBridgeInfo[var].visited) annotateBridgeHelper(var, &time);
- }
- }
-
- // Re-partition the network by treating bridges as no edge.
- void add(const RandomVariableNode& var) {
- auto parent1 = var->parent1;
- auto parent2 = var->parent2;
- if (mBridgeInfo[var].isParent1Bridge) var->parent1 = nullptr;
- if (mBridgeInfo[var].isParent2Bridge) var->parent2 = nullptr;
- DisjointNetwork::add(var);
- var->parent1 = parent1;
- var->parent2 = parent2;
- }
-
- // Add bridge nodes to the local network and remove single node subnet.
- std::vector<LocalNetwork> get(int timestamp) {
- std::vector<LocalNetwork> res;
- for (auto& pair : mEvalOrderMap) {
- // We do not need to evaluate subnet with only a single node.
- if (pair.second.size() == 1 && pair.second[0]->parent1 == nullptr) continue;
- res.emplace_back();
- for (const auto& var : pair.second) {
- if (mBridgeInfo[var].isParent1Bridge) {
- res.back().evalOrder.push_back(var->parent1);
- res.back().bridgeNodes.push_back(var->parent1);
- }
- if (mBridgeInfo[var].isParent2Bridge) {
- res.back().evalOrder.push_back(var->parent2);
- res.back().bridgeNodes.push_back(var->parent2);
- }
- res.back().evalOrder.push_back(var);
- }
- res.back().timestamp = timestamp;
- }
- return res;
- }
-
- // For bridge discovery algorithm.
- struct BridgeInfo {
- bool isParent1Bridge = false;
- bool isParent2Bridge = false;
- int discoveryTime = 0;
- int lowTime = 0;
- bool visited = false;
- std::shared_ptr<RandomVariableBase> parent = nullptr;
- };
- std::unordered_map<RandomVariableNode, BridgeInfo> mBridgeInfo;
-};
-
-// Evaluate subnets repeatedly until converge.
-// Class T_Subnet must have member evalOrder, timestamp, and member function eval.
-template <class T_Subnet>
-inline bool evalSubnetsRepeatedly(std::vector<T_Subnet>* subnets, EvalContext* context) {
- bool terminate = false;
- while (!terminate) {
- terminate = true;
- for (auto& subnet : *subnets) {
- if (needEvaluate(subnet.evalOrder, subnet.timestamp, context)) {
- if (!subnet.eval(context)) return false;
- subnet.timestamp = RandomVariableNetwork::get()->getGlobalTime();
- terminate = false;
- }
- }
- }
- return true;
-}
-
-// Evaluate the subnet by first partitioning it further into LocalNetworks.
-static bool evalSubnetWithLocalNetwork(const EvaluationOrder& evalOrder, int timestamp,
- EvalContext* context) {
- NN_FUZZER_LOG << "Evaluate with local network";
- auto localNetworks = GraphPartitioner().partition(evalOrder, timestamp);
- return evalSubnetsRepeatedly(&localNetworks, context);
-}
-
-struct LeafNetwork {
- EvaluationOrder evalOrder;
- int timestamp = 0;
- LeafNetwork(const RandomVariableNode& var, int timestamp) : timestamp(timestamp) {
- std::set<RandomVariableNode> visited;
- constructorHelper(var, &visited);
- }
- // Construct the leaf network by recursively including parent nodes.
- void constructorHelper(const RandomVariableNode& var, std::set<RandomVariableNode>* visited) {
- if (var == nullptr || visited->find(var) != visited->end()) return;
- constructorHelper(var->parent1, visited);
- constructorHelper(var->parent2, visited);
- visited->insert(var);
- evalOrder.push_back(var);
- }
- bool eval(EvalContext* context) {
- return evalSubnetWithLocalNetwork(evalOrder, timestamp, context);
- }
-};
-
-// Evaluate the subnet by leaf network.
-// NOTE: This algorithm will only produce correct result for *most* of the time (> 99%).
-// The random graph generator is expected to retry if it fails.
-static bool evalSubnetWithLeafNetwork(const EvaluationOrder& evalOrder, int timestamp,
- EvalContext* context) {
- NN_FUZZER_LOG << "Evaluate with leaf network";
- // Construct leaf networks.
- std::vector<LeafNetwork> leafNetworks;
- for (const auto& var : evalOrder) {
- if (var->children.empty()) {
- NN_FUZZER_LOG << "Found leaf " << toString(var, context);
- leafNetworks.emplace_back(var, timestamp);
- }
- }
- return evalSubnetsRepeatedly(&leafNetworks, context);
-}
-
-void RandomVariableNetwork::addDimensionProd(const std::vector<RandomVariable>& dims) {
- if (dims.size() <= 1) return;
- EvaluationOrder order;
- for (const auto& dim : dims) order.push_back(dim.get());
- mDimProd.push_back(order);
-}
-
-bool enforceDimProd(const std::vector<EvaluationOrder>& mDimProd,
- const std::unordered_map<RandomVariableNode, int>& indexMap,
- EvalContext* context, std::set<int>* dirtySubnets) {
- for (auto& evalOrder : mDimProd) {
- NN_FUZZER_LOG << " Dimension product network size = " << evalOrder.size();
- // Initialize EvalInfo of each RandomVariable.
- for (auto& var : evalOrder) {
- if (context->find(var) == context->end()) context->emplace(var, var);
- NN_FUZZER_LOG << " - " << toString(var, context);
- }
-
- // Enforce the product of the dimension values below kMaxValue:
- // max(dimA) = kMaxValue / (min(dimB) * min(dimC) * ...)
- int prod = 1;
- for (const auto& var : evalOrder) prod *= (*context->at(var).committed.begin());
- for (auto& var : evalOrder) {
- auto& committed = context->at(var).committed;
- int maxValue = kMaxValue / (prod / *committed.begin());
- auto it = committed.upper_bound(maxValue);
- // var has empty range -> no solution.
- if (it == committed.begin()) return false;
- // The range is not modified -> continue.
- if (it == committed.end()) continue;
- // The range is modified -> the subnet of var is dirty, i.e. needs re-evaluation.
- committed.erase(it, committed.end());
- context->at(var).timestamp = RandomVariableNetwork::get()->getGlobalTime();
- dirtySubnets->insert(indexMap.at(var));
- }
- }
- return true;
-}
-
-bool RandomVariableNetwork::evalRange() {
- constexpr uint64_t kMaxNumCombinationsWithBruteForce = 500;
- constexpr uint64_t kMaxNumCombinationsWithLocalNetwork = 1e5;
- NN_FUZZER_LOG << "Evaluate on " << mEvalOrderMap.size() << " sub-networks";
- EvalContext context;
- std::set<int> dirtySubnets; // Which subnets needs evaluation.
- for (auto& pair : mEvalOrderMap) {
- const auto& evalOrder = pair.second;
- // Decide whether needs evaluation by timestamp -- if no range has changed after the last
- // evaluation, then the subnet does not need re-evaluation.
- if (evalOrder.size() == 1 || !needEvaluate(evalOrder, mTimestamp)) continue;
- dirtySubnets.insert(pair.first);
- }
- if (!enforceDimProd(mDimProd, mIndexMap, &context, &dirtySubnets)) return false;
-
- // Repeat until the ranges converge.
- while (!dirtySubnets.empty()) {
- for (int ind : dirtySubnets) {
- const auto& evalOrder = mEvalOrderMap[ind];
- NN_FUZZER_LOG << " Sub-network #" << ind << " size = " << evalOrder.size();
-
- // Initialize EvalInfo of each RandomVariable.
- for (auto& var : evalOrder) {
- if (context.find(var) == context.end()) context.emplace(var, var);
- NN_FUZZER_LOG << " - " << toString(var, &context);
- }
-
- // Dispatch to different algorithm according to search range.
- bool success;
- uint64_t numCombinations = getNumCombinations(evalOrder);
- if (numCombinations <= kMaxNumCombinationsWithBruteForce) {
- success = evalSubnetWithBruteForce(evalOrder, &context);
- } else if (numCombinations <= kMaxNumCombinationsWithLocalNetwork) {
- success = evalSubnetWithLocalNetwork(evalOrder, mTimestamp, &context);
- } else {
- success = evalSubnetWithLeafNetwork(evalOrder, mTimestamp, &context);
- }
- if (!success) return false;
- }
- dirtySubnets.clear();
- if (!enforceDimProd(mDimProd, mIndexMap, &context, &dirtySubnets)) return false;
- }
- // A successful evaluation, update RandomVariables from EvalContext.
- for (auto& pair : context) pair.second.updateRange();
- mTimestamp = getGlobalTime();
- NN_FUZZER_LOG << "Finish range evaluation";
- return true;
-}
-
-static void unsetEqual(const RandomVariableNode& node) {
- if (node == nullptr) return;
- NN_FUZZER_LOG << "Unset equality of var" << node->index;
- auto weakPtrEqual = [&node](const std::weak_ptr<RandomVariableBase>& ptr) {
- return ptr.lock() == node;
- };
- RandomVariableNode parent1 = node->parent1, parent2 = node->parent2;
- parent1->children.erase(
- std::find_if(parent1->children.begin(), parent1->children.end(), weakPtrEqual));
- node->parent1 = nullptr;
- if (parent2 != nullptr) {
- // For Equal.
- parent2->children.erase(
- std::find_if(parent2->children.begin(), parent2->children.end(), weakPtrEqual));
- node->parent2 = nullptr;
- } else {
- // For UnaryEqual.
- node->type = RandomVariableType::FREE;
- node->op = nullptr;
- }
-}
-
-// A class to revert all the changes made to RandomVariableNetwork since the Reverter object is
-// constructed. Only used when setEqualIfCompatible results in incompatible.
-class RandomVariableNetwork::Reverter {
- public:
- // Take a snapshot of RandomVariableNetwork when Reverter is constructed.
- Reverter() : mSnapshot(*RandomVariableNetwork::get()) {}
- // Add constraint (Equal) nodes to the reverter.
- void addNode(const RandomVariableNode& node) { mEqualNodes.push_back(node); }
- void revert() {
- NN_FUZZER_LOG << "Revert RandomVariableNetwork";
- // Release the constraints.
- for (const auto& node : mEqualNodes) unsetEqual(node);
- // Reset all member variables.
- *RandomVariableNetwork::get() = std::move(mSnapshot);
- }
-
- private:
- Reverter(const Reverter&) = delete;
- Reverter& operator=(const Reverter&) = delete;
- RandomVariableNetwork mSnapshot;
- std::vector<RandomVariableNode> mEqualNodes;
-};
-
-bool RandomVariableNetwork::setEqualIfCompatible(const std::vector<RandomVariable>& lhs,
- const std::vector<RandomVariable>& rhs) {
- NN_FUZZER_LOG << "Check compatibility of {" << joinStr(", ", lhs) << "} and {"
- << joinStr(", ", rhs) << "}";
- if (lhs.size() != rhs.size()) return false;
- Reverter reverter;
- bool result = true;
- for (size_t i = 0; i < lhs.size(); i++) {
- auto node = lhs[i].setEqual(rhs[i]).get();
- reverter.addNode(node);
- // Early terminate if there is no common choice between two ranges.
- if (node != nullptr && node->range.empty()) result = false;
- }
- result = result && evalRange();
- if (!result) reverter.revert();
- NN_FUZZER_LOG << "setEqualIfCompatible: " << (result ? "[COMPATIBLE]" : "[INCOMPATIBLE]");
- return result;
-}
-
-bool RandomVariableNetwork::freeze() {
- NN_FUZZER_LOG << "Freeze the random network";
- if (!evalRange()) return false;
-
- std::vector<RandomVariableNode> nodes;
- for (const auto& pair : mEvalOrderMap) {
- // Find all FREE RandomVariables in the subnet.
- for (const auto& var : pair.second) {
- if (var->type == RandomVariableType::FREE) nodes.push_back(var);
- }
- }
-
- // Randomly shuffle the order, this is for a more uniform randomness.
- randomShuffle(&nodes);
-
- // An inefficient algorithm that does freeze -> re-evaluate for every FREE RandomVariable.
- // TODO: Might be able to optimize this.
- for (const auto& var : nodes) {
- if (var->type != RandomVariableType::FREE) continue;
- size_t size = var->range.size();
- NN_FUZZER_LOG << "Freeze " << toString(var);
- var->freeze();
- NN_FUZZER_LOG << " " << toString(var);
- // There is no need to re-evaluate if the FREE RandomVariable have only one choice.
- if (size > 1) {
- var->updateTimestamp();
- if (!evalRange()) {
- NN_FUZZER_LOG << "Freeze failed at " << toString(var);
- return false;
- }
- }
- }
- NN_FUZZER_LOG << "Finish freezing the random network";
- return true;
-}
-
-} // namespace fuzzing_test
-} // namespace nn
-} // namespace android
+/* + * Copyright (C) 2019 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 "RandomVariable.h" + +#include <algorithm> +#include <memory> +#include <set> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "RandomGraphGeneratorUtils.h" + +namespace android { +namespace nn { +namespace fuzzing_test { + +unsigned int RandomVariableBase::globalIndex = 0; +int RandomVariable::defaultValue = 10; + +RandomVariableBase::RandomVariableBase(int value) + : index(globalIndex++), + type(RandomVariableType::CONST), + range(value), + value(value), + timestamp(RandomVariableNetwork::get()->getGlobalTime()) {} + +RandomVariableBase::RandomVariableBase(int lower, int upper) + : index(globalIndex++), + type(RandomVariableType::FREE), + range(lower, upper), + timestamp(RandomVariableNetwork::get()->getGlobalTime()) {} + +RandomVariableBase::RandomVariableBase(const std::vector<int>& choices) + : index(globalIndex++), + type(RandomVariableType::FREE), + range(choices), + timestamp(RandomVariableNetwork::get()->getGlobalTime()) {} + +RandomVariableBase::RandomVariableBase(const RandomVariableNode& lhs, const RandomVariableNode& rhs, + const std::shared_ptr<const IRandomVariableOp>& op) + : index(globalIndex++), + type(RandomVariableType::OP), + range(op->getInitRange(lhs->range, rhs == nullptr ? RandomVariableRange(0) : rhs->range)), + op(op), + parent1(lhs), + parent2(rhs), + timestamp(RandomVariableNetwork::get()->getGlobalTime()) {} + +void RandomVariableRange::setRange(int lower, int upper) { + // kInvalidValue indicates unlimited bound. + auto head = lower == kInvalidValue ? mChoices.begin() + : std::lower_bound(mChoices.begin(), mChoices.end(), lower); + auto tail = upper == kInvalidValue ? mChoices.end() + : std::upper_bound(mChoices.begin(), mChoices.end(), upper); + NN_FUZZER_CHECK(head <= tail) << "Invalid range!"; + if (head != mChoices.begin() || tail != mChoices.end()) { + mChoices = std::vector<int>(head, tail); + } +} + +int RandomVariableRange::toConst() { + if (mChoices.size() > 1) mChoices = {getRandomChoice(mChoices)}; + return mChoices[0]; +} + +RandomVariableRange operator&(const RandomVariableRange& lhs, const RandomVariableRange& rhs) { + std::vector<int> result(lhs.size() + rhs.size()); + auto it = std::set_intersection(lhs.mChoices.begin(), lhs.mChoices.end(), rhs.mChoices.begin(), + rhs.mChoices.end(), result.begin()); + result.resize(it - result.begin()); + return RandomVariableRange(std::move(result)); +} + +void RandomVariableBase::freeze() { + if (type == RandomVariableType::CONST) return; + value = range.toConst(); + type = RandomVariableType::CONST; +} + +int RandomVariableBase::getValue() const { + switch (type) { + case RandomVariableType::CONST: + return value; + case RandomVariableType::OP: + return op->eval(parent1->getValue(), parent2 == nullptr ? 0 : parent2->getValue()); + default: + NN_FUZZER_CHECK(false) << "Invalid type when getting value of var" << index; + return 0; + } +} + +void RandomVariableBase::updateTimestamp() { + timestamp = RandomVariableNetwork::get()->getGlobalTime(); + NN_FUZZER_LOG << "Update timestamp of var" << index << " to " << timestamp; +} + +RandomVariable::RandomVariable(int value) : mVar(new RandomVariableBase(value)) { + NN_FUZZER_LOG << "New RandomVariable " << mVar; + RandomVariableNetwork::get()->add(mVar); +} +RandomVariable::RandomVariable(int lower, int upper) : mVar(new RandomVariableBase(lower, upper)) { + NN_FUZZER_LOG << "New RandomVariable " << mVar; + RandomVariableNetwork::get()->add(mVar); +} +RandomVariable::RandomVariable(const std::vector<int>& choices) + : mVar(new RandomVariableBase(choices)) { + NN_FUZZER_LOG << "New RandomVariable " << mVar; + RandomVariableNetwork::get()->add(mVar); +} +RandomVariable::RandomVariable(RandomVariableType type) + : mVar(new RandomVariableBase(1, defaultValue)) { + NN_FUZZER_CHECK(type == RandomVariableType::FREE); + NN_FUZZER_LOG << "New RandomVariable " << mVar; + RandomVariableNetwork::get()->add(mVar); +} +RandomVariable::RandomVariable(const RandomVariable& lhs, const RandomVariable& rhs, + const std::shared_ptr<const IRandomVariableOp>& op) + : mVar(new RandomVariableBase(lhs.get(), rhs.get(), op)) { + // Make a copy if the parent is CONST. This will resolve the fake dependency problem. + if (mVar->parent1->type == RandomVariableType::CONST) { + mVar->parent1 = RandomVariable(mVar->parent1->value).get(); + } + if (mVar->parent2 != nullptr && mVar->parent2->type == RandomVariableType::CONST) { + mVar->parent2 = RandomVariable(mVar->parent2->value).get(); + } + mVar->parent1->children.push_back(mVar); + if (mVar->parent2 != nullptr) mVar->parent2->children.push_back(mVar); + RandomVariableNetwork::get()->add(mVar); + NN_FUZZER_LOG << "New RandomVariable " << mVar; +} + +void RandomVariable::setRange(int lower, int upper) { + NN_FUZZER_CHECK(mVar != nullptr) << "setRange() on nullptr"; + NN_FUZZER_LOG << "Set range [" << lower << ", " << upper << "] on var" << mVar->index; + size_t oldSize = mVar->range.size(); + mVar->range.setRange(lower, upper); + // Only update the timestamp if the range is *indeed* narrowed down. + if (mVar->range.size() != oldSize) mVar->updateTimestamp(); +} + +RandomVariableRange IRandomVariableOp::getInitRange(const RandomVariableRange& lhs, + const RandomVariableRange& rhs) const { + std::set<int> st; + for (auto i : lhs.getChoices()) { + for (auto j : rhs.getChoices()) { + int res = this->eval(i, j); + if (res > kMaxValue || res < -kMaxValue) continue; + st.insert(res); + } + } + return RandomVariableRange(st); +} + +// Check if the range contains exactly all values in [min, max]. +static inline bool isContinuous(const std::set<int>* range) { + return (*(range->rbegin()) - *(range->begin()) + 1) == static_cast<int>(range->size()); +} + +// Fill the set with a range of values specified by [lower, upper]. +static inline void fillRange(std::set<int>* range, int lower, int upper) { + for (int i = lower; i <= upper; i++) range->insert(i); +} + +// The slowest algorithm: iterate through every combinations of parents and save the valid pairs. +void IRandomVariableOp::eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>* childIn, std::set<int>* parent1Out, + std::set<int>* parent2Out, std::set<int>* childOut) const { + // Avoid the binary search if the child is a closed range. + bool isChildInContinuous = isContinuous(childIn); + std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()}; + for (auto i : *parent1In) { + bool valid = false; + for (auto j : *parent2In) { + int res = this->eval(i, j); + // Avoid the binary search if obviously out of range. + if (res > child.second || res < child.first) continue; + if (isChildInContinuous || childIn->find(res) != childIn->end()) { + parent2Out->insert(j); + childOut->insert(res); + valid = true; + } + } + if (valid) parent1Out->insert(i); + } +} + +// A helper template to make a class into a Singleton. +template <class T> +class Singleton : public T { + public: + static const std::shared_ptr<const T>& get() { + static std::shared_ptr<const T> instance(new T); + return instance; + } +}; + +// A set of operations that only compute on a single input value. +class IUnaryOp : public IRandomVariableOp { + public: + using IRandomVariableOp::eval; + virtual int eval(int val) const = 0; + virtual int eval(int lhs, int) const override { return eval(lhs); } + // The slowest algorithm: iterate through every value of the parent and save the valid one. + virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>* childIn, std::set<int>* parent1Out, + std::set<int>* parent2Out, std::set<int>* childOut) const override { + NN_FUZZER_CHECK(parent2In == nullptr); + NN_FUZZER_CHECK(parent2Out == nullptr); + bool isChildInContinuous = isContinuous(childIn); + std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()}; + for (auto i : *parent1In) { + int res = this->eval(i); + if (res > child.second || res < child.first) continue; + if (isChildInContinuous || childIn->find(res) != childIn->end()) { + parent1Out->insert(i); + childOut->insert(res); + } + } + } +}; + +// A set of operations that only check conditional constraints. +class IConstraintOp : public IRandomVariableOp { + public: + using IRandomVariableOp::eval; + virtual bool check(int lhs, int rhs) const = 0; + virtual int eval(int lhs, int rhs) const override { + return check(lhs, rhs) ? 0 : kInvalidValue; + } + // The range for a constraint op is always {0}. + virtual RandomVariableRange getInitRange(const RandomVariableRange&, + const RandomVariableRange&) const override { + return RandomVariableRange(0); + } + // The slowest algorithm: + // iterate through every combinations of parents and save the valid pairs. + virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>*, std::set<int>* parent1Out, std::set<int>* parent2Out, + std::set<int>* childOut) const override { + for (auto i : *parent1In) { + bool valid = false; + for (auto j : *parent2In) { + if (this->check(i, j)) { + parent2Out->insert(j); + valid = true; + } + } + if (valid) parent1Out->insert(i); + } + if (!parent1Out->empty()) childOut->insert(0); + } +}; + +class Addition : public IRandomVariableOp { + public: + virtual int eval(int lhs, int rhs) const override { return lhs + rhs; } + virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs, + const RandomVariableRange& rhs) const override { + return RandomVariableRange(lhs.min() + rhs.min(), lhs.max() + rhs.max()); + } + virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>* childIn, std::set<int>* parent1Out, + std::set<int>* parent2Out, std::set<int>* childOut) const override { + if (!isContinuous(parent1In) || !isContinuous(parent2In) || !isContinuous(childIn)) { + IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out, + childOut); + } else { + // For parents and child with close range, the out range can be computed directly + // without iterations. + std::pair<int, int> parent1 = {*parent1In->begin(), *parent1In->rbegin()}; + std::pair<int, int> parent2 = {*parent2In->begin(), *parent2In->rbegin()}; + std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()}; + + // From ranges for parent, evaluate range for child. + // [a, b] + [c, d] -> [a + c, b + d] + fillRange(childOut, std::max(child.first, parent1.first + parent2.first), + std::min(child.second, parent1.second + parent2.second)); + + // From ranges for child and one parent, evaluate range for another parent. + // [a, b] - [c, d] -> [a - d, b - c] + fillRange(parent1Out, std::max(parent1.first, child.first - parent2.second), + std::min(parent1.second, child.second - parent2.first)); + fillRange(parent2Out, std::max(parent2.first, child.first - parent1.second), + std::min(parent2.second, child.second - parent1.first)); + } + } + virtual const char* getName() const override { return "ADD"; } +}; + +class Subtraction : public IRandomVariableOp { + public: + virtual int eval(int lhs, int rhs) const override { return lhs - rhs; } + virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs, + const RandomVariableRange& rhs) const override { + return RandomVariableRange(lhs.min() - rhs.max(), lhs.max() - rhs.min()); + } + virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>* childIn, std::set<int>* parent1Out, + std::set<int>* parent2Out, std::set<int>* childOut) const override { + if (!isContinuous(parent1In) || !isContinuous(parent2In) || !isContinuous(childIn)) { + IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out, + childOut); + } else { + // Similar algorithm as Addition. + std::pair<int, int> parent1 = {*parent1In->begin(), *parent1In->rbegin()}; + std::pair<int, int> parent2 = {*parent2In->begin(), *parent2In->rbegin()}; + std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()}; + fillRange(childOut, std::max(child.first, parent1.first - parent2.second), + std::min(child.second, parent1.second - parent2.first)); + fillRange(parent1Out, std::max(parent1.first, child.first + parent2.first), + std::min(parent1.second, child.second + parent2.second)); + fillRange(parent2Out, std::max(parent2.first, parent1.first - child.second), + std::min(parent2.second, parent1.second - child.first)); + } + } + virtual const char* getName() const override { return "SUB"; } +}; + +class Multiplication : public IRandomVariableOp { + public: + virtual int eval(int lhs, int rhs) const override { return lhs * rhs; } + virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs, + const RandomVariableRange& rhs) const override { + if (lhs.min() < 0 || rhs.min() < 0) { + return IRandomVariableOp::getInitRange(lhs, rhs); + } else { + int lower = std::min(lhs.min() * rhs.min(), kMaxValue); + int upper = std::min(lhs.max() * rhs.max(), kMaxValue); + return RandomVariableRange(lower, upper); + } + } + virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>* childIn, std::set<int>* parent1Out, + std::set<int>* parent2Out, std::set<int>* childOut) const override { + if (*parent1In->begin() < 0 || *parent2In->begin() < 0 || *childIn->begin() < 0) { + IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out, + childOut); + } else { + bool isChildInContinuous = isContinuous(childIn); + std::pair<int, int> child = {*childIn->begin(), *childIn->rbegin()}; + for (auto i : *parent1In) { + bool valid = false; + for (auto j : *parent2In) { + int res = this->eval(i, j); + // Since MUL increases monotonically with one value, break the loop if the + // result is larger than the limit. + if (res > child.second) break; + if (res < child.first) continue; + if (isChildInContinuous || childIn->find(res) != childIn->end()) { + valid = true; + parent2Out->insert(j); + childOut->insert(res); + } + } + if (valid) parent1Out->insert(i); + } + } + } + virtual const char* getName() const override { return "MUL"; } +}; + +class Division : public IRandomVariableOp { + public: + virtual int eval(int lhs, int rhs) const override { + return rhs == 0 ? kInvalidValue : lhs / rhs; + } + virtual RandomVariableRange getInitRange(const RandomVariableRange& lhs, + const RandomVariableRange& rhs) const override { + if (lhs.min() < 0 || rhs.min() <= 0) { + return IRandomVariableOp::getInitRange(lhs, rhs); + } else { + return RandomVariableRange(lhs.min() / rhs.max(), lhs.max() / rhs.min()); + } + } + virtual const char* getName() const override { return "DIV"; } +}; + +class ExactDivision : public Division { + public: + virtual int eval(int lhs, int rhs) const override { + return (rhs == 0 || lhs % rhs != 0) ? kInvalidValue : lhs / rhs; + } + virtual const char* getName() const override { return "EXACT_DIV"; } +}; + +class Modulo : public IRandomVariableOp { + public: + virtual int eval(int lhs, int rhs) const override { + return rhs == 0 ? kInvalidValue : lhs % rhs; + } + virtual RandomVariableRange getInitRange(const RandomVariableRange&, + const RandomVariableRange& rhs) const override { + return RandomVariableRange(0, rhs.max()); + } + virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>* childIn, std::set<int>* parent1Out, + std::set<int>* parent2Out, std::set<int>* childOut) const override { + if (*childIn->begin() != 0 || childIn->size() != 1u) { + IRandomVariableOp::eval(parent1In, parent2In, childIn, parent1Out, parent2Out, + childOut); + } else { + // For the special case that child is a const 0, it would be faster if the range for + // parents are evaluated separately. + + // Evaluate parent1 directly. + for (auto i : *parent1In) { + for (auto j : *parent2In) { + if (i % j == 0) { + parent1Out->insert(i); + break; + } + } + } + // Evaluate parent2, see if a multiple of parent2 value can be found in parent1. + int parent1Max = *parent1In->rbegin(); + for (auto i : *parent2In) { + int jMax = parent1Max / i; + for (int j = 1; j <= jMax; j++) { + if (parent1In->find(i * j) != parent1In->end()) { + parent2Out->insert(i); + break; + } + } + } + if (!parent1Out->empty()) childOut->insert(0); + } + } + virtual const char* getName() const override { return "MOD"; } +}; + +class Maximum : public IRandomVariableOp { + public: + virtual int eval(int lhs, int rhs) const override { return std::max(lhs, rhs); } + virtual const char* getName() const override { return "MAX"; } +}; + +class Minimum : public IRandomVariableOp { + public: + virtual int eval(int lhs, int rhs) const override { return std::min(lhs, rhs); } + virtual const char* getName() const override { return "MIN"; } +}; + +class Square : public IUnaryOp { + public: + virtual int eval(int val) const override { return val * val; } + virtual const char* getName() const override { return "SQUARE"; } +}; + +class UnaryEqual : public IUnaryOp { + public: + virtual int eval(int val) const override { return val; } + virtual const char* getName() const override { return "UNARY_EQUAL"; } +}; + +class Equal : public IConstraintOp { + public: + virtual bool check(int lhs, int rhs) const override { return lhs == rhs; } + virtual void eval(const std::set<int>* parent1In, const std::set<int>* parent2In, + const std::set<int>* childIn, std::set<int>* parent1Out, + std::set<int>* parent2Out, std::set<int>* childOut) const override { + NN_FUZZER_CHECK(childIn->size() == 1u && *childIn->begin() == 0); + // The intersection of two sets can be found in O(n). + std::set_intersection(parent1In->begin(), parent1In->end(), parent2In->begin(), + parent2In->end(), std::inserter(*parent1Out, parent1Out->begin())); + *parent2Out = *parent1Out; + childOut->insert(0); + } + virtual const char* getName() const override { return "EQUAL"; } +}; + +class GreaterThan : public IConstraintOp { + public: + virtual bool check(int lhs, int rhs) const override { return lhs > rhs; } + virtual const char* getName() const override { return "GREATER_THAN"; } +}; + +class GreaterEqual : public IConstraintOp { + public: + virtual bool check(int lhs, int rhs) const override { return lhs >= rhs; } + virtual const char* getName() const override { return "GREATER_EQUAL"; } +}; + +class FloatMultiplication : public IUnaryOp { + public: + FloatMultiplication(float multiplicand) : mMultiplicand(multiplicand) {} + virtual int eval(int val) const override { + return static_cast<int>(std::floor(static_cast<float>(val) * mMultiplicand)); + } + virtual const char* getName() const override { return "MUL_FLOAT"; } + + private: + float mMultiplicand; +}; + +// Arithmetic operators and methods on RandomVariables will create OP RandomVariableNodes. +// Since there must be at most one edge between two RandomVariableNodes, we have to do something +// special when both sides are refering to the same node. + +RandomVariable operator+(const RandomVariable& lhs, const RandomVariable& rhs) { + return lhs.get() == rhs.get() ? RandomVariable(lhs, 2, Singleton<Multiplication>::get()) + : RandomVariable(lhs, rhs, Singleton<Addition>::get()); +} +RandomVariable operator-(const RandomVariable& lhs, const RandomVariable& rhs) { + return lhs.get() == rhs.get() ? RandomVariable(0) + : RandomVariable(lhs, rhs, Singleton<Subtraction>::get()); +} +RandomVariable operator*(const RandomVariable& lhs, const RandomVariable& rhs) { + return lhs.get() == rhs.get() ? RandomVariable(lhs, RandomVariable(), Singleton<Square>::get()) + : RandomVariable(lhs, rhs, Singleton<Multiplication>::get()); +} +RandomVariable operator*(const RandomVariable& lhs, const float& rhs) { + return RandomVariable(lhs, RandomVariable(), std::make_shared<FloatMultiplication>(rhs)); +} +RandomVariable operator/(const RandomVariable& lhs, const RandomVariable& rhs) { + return lhs.get() == rhs.get() ? RandomVariable(1) + : RandomVariable(lhs, rhs, Singleton<Division>::get()); +} +RandomVariable operator%(const RandomVariable& lhs, const RandomVariable& rhs) { + return lhs.get() == rhs.get() ? RandomVariable(0) + : RandomVariable(lhs, rhs, Singleton<Modulo>::get()); +} +RandomVariable max(const RandomVariable& lhs, const RandomVariable& rhs) { + return lhs.get() == rhs.get() ? lhs : RandomVariable(lhs, rhs, Singleton<Maximum>::get()); +} +RandomVariable min(const RandomVariable& lhs, const RandomVariable& rhs) { + return lhs.get() == rhs.get() ? lhs : RandomVariable(lhs, rhs, Singleton<Minimum>::get()); +} + +RandomVariable RandomVariable::exactDiv(const RandomVariable& other) { + return mVar == other.get() ? RandomVariable(1) + : RandomVariable(*this, other, Singleton<ExactDivision>::get()); +} + +RandomVariable RandomVariable::setEqual(const RandomVariable& other) const { + RandomVariableNode node1 = mVar, node2 = other.get(); + NN_FUZZER_LOG << "Set equality of var" << node1->index << " and var" << node2->index; + + // Do not setEqual on the same pair twice. + if (node1 == node2 || (node1->op == Singleton<UnaryEqual>::get() && node1->parent1 == node2) || + (node2->op == Singleton<UnaryEqual>::get() && node2->parent1 == node1)) { + NN_FUZZER_LOG << "Already equal. Return."; + return RandomVariable(); + } + + // If possible, always try UnaryEqual first to reduce the search space. + // UnaryEqual can be used if node B is FREE and is evaluated later than node A. + // TODO: Reduce code duplication. + if (RandomVariableNetwork::get()->isSubordinate(node1, node2)) { + NN_FUZZER_LOG << " Make var" << node2->index << " a child of var" << node1->index; + node2->type = RandomVariableType::OP; + node2->parent1 = node1; + node2->op = Singleton<UnaryEqual>::get(); + node1->children.push_back(node2); + RandomVariableNetwork::get()->join(node1, node2); + node1->updateTimestamp(); + return other; + } + if (RandomVariableNetwork::get()->isSubordinate(node2, node1)) { + NN_FUZZER_LOG << " Make var" << node1->index << " a child of var" << node2->index; + node1->type = RandomVariableType::OP; + node1->parent1 = node2; + node1->op = Singleton<UnaryEqual>::get(); + node2->children.push_back(node1); + RandomVariableNetwork::get()->join(node2, node1); + node1->updateTimestamp(); + return *this; + } + return RandomVariable(*this, other, Singleton<Equal>::get()); +} + +RandomVariable RandomVariable::setGreaterThan(const RandomVariable& other) const { + NN_FUZZER_CHECK(mVar != other.get()); + return RandomVariable(*this, other, Singleton<GreaterThan>::get()); +} +RandomVariable RandomVariable::setGreaterEqual(const RandomVariable& other) const { + return mVar == other.get() ? *this + : RandomVariable(*this, other, Singleton<GreaterEqual>::get()); +} + +void DisjointNetwork::add(const RandomVariableNode& var) { + // Find the subnet index of the parents and decide the index for var. + int ind1 = var->parent1 == nullptr ? -1 : mIndexMap[var->parent1]; + int ind2 = var->parent2 == nullptr ? -1 : mIndexMap[var->parent2]; + int ind = join(ind1, ind2); + // If no parent, put it into a new subnet component. + if (ind == -1) ind = mNextIndex++; + NN_FUZZER_LOG << "Add RandomVariable var" << var->index << " to network #" << ind; + mIndexMap[var] = ind; + mEvalOrderMap[ind].push_back(var); +} + +int DisjointNetwork::join(int ind1, int ind2) { + if (ind1 == -1) return ind2; + if (ind2 == -1) return ind1; + if (ind1 == ind2) return ind1; + NN_FUZZER_LOG << "Join network #" << ind1 << " and #" << ind2; + auto &order1 = mEvalOrderMap[ind1], &order2 = mEvalOrderMap[ind2]; + // Append every node in ind2 to the end of ind1 + for (const auto& var : order2) { + order1.push_back(var); + mIndexMap[var] = ind1; + } + // Remove ind2 from mEvalOrderMap. + mEvalOrderMap.erase(mEvalOrderMap.find(ind2)); + return ind1; +} + +RandomVariableNetwork* RandomVariableNetwork::get() { + static RandomVariableNetwork instance; + return &instance; +} + +void RandomVariableNetwork::initialize(int defaultValue) { + RandomVariableBase::globalIndex = 0; + RandomVariable::defaultValue = defaultValue; + mIndexMap.clear(); + mEvalOrderMap.clear(); + mDimProd.clear(); + mNextIndex = 0; + mGlobalTime = 0; + mTimestamp = -1; +} + +bool RandomVariableNetwork::isSubordinate(const RandomVariableNode& node1, + const RandomVariableNode& node2) { + if (node2->type != RandomVariableType::FREE) return false; + int ind1 = mIndexMap[node1]; + // node2 is of a different subnet. + if (ind1 != mIndexMap[node2]) return true; + for (const auto& node : mEvalOrderMap[ind1]) { + if (node == node2) return false; + // node2 is of the same subnet but evaluated later than node1. + if (node == node1) return true; + } + NN_FUZZER_CHECK(false) << "Code executed in non-reachable region."; + return false; +} + +struct EvalInfo { + // The RandomVariableNode that this EvalInfo is associated with. + // var->value is the current value during evaluation. + RandomVariableNode var; + + // The RandomVariable value is staged when a valid combination is found. + std::set<int> staging; + + // The staging values are committed after a subnet evaluation. + std::set<int> committed; + + // Keeps track of the latest timestamp that committed is updated. + int timestamp; + + // For evalSubnetWithLocalNetwork. + RandomVariableType originalType; + + // Should only invoke eval on OP RandomVariable. + bool eval() { + NN_FUZZER_CHECK(var->type == RandomVariableType::OP); + var->value = var->op->eval(var->parent1->value, + var->parent2 == nullptr ? 0 : var->parent2->value); + if (var->value == kInvalidValue) return false; + return committed.find(var->value) != committed.end(); + } + void stage() { staging.insert(var->value); } + void commit() { + // Only update committed and timestamp if the range is *indeed* changed. + if (staging.size() != committed.size()) { + committed = std::move(staging); + timestamp = RandomVariableNetwork::get()->getGlobalTime(); + } + staging.clear(); + } + void updateRange() { + // Only update range and timestamp if the range is *indeed* changed. + if (committed.size() != var->range.size()) { + var->range = RandomVariableRange(committed); + var->timestamp = timestamp; + } + committed.clear(); + } + + EvalInfo(const RandomVariableNode& var) + : var(var), + committed(var->range.getChoices().begin(), var->range.getChoices().end()), + timestamp(var->timestamp) {} +}; +using EvalContext = std::unordered_map<RandomVariableNode, EvalInfo>; + +// For logging only. +inline std::string toString(const RandomVariableNode& var, EvalContext* context) { + std::stringstream ss; + ss << "var" << var->index << " = "; + const auto& committed = context->at(var).committed; + switch (var->type) { + case RandomVariableType::FREE: + ss << "FREE [" + << joinStr(", ", 20, std::vector<int>(committed.begin(), committed.end())) << "]"; + break; + case RandomVariableType::CONST: + ss << "CONST " << var->value; + break; + case RandomVariableType::OP: + ss << "var" << var->parent1->index << " " << var->op->getName(); + if (var->parent2 != nullptr) ss << " var" << var->parent2->index; + ss << ", [" << joinStr(", ", 20, std::vector<int>(committed.begin(), committed.end())) + << "]"; + break; + default: + NN_FUZZER_CHECK(false); + } + ss << ", timestamp = " << context->at(var).timestamp; + return ss.str(); +} + +// Check if the subnet needs to be re-evaluated by comparing the timestamps. +static inline bool needEvaluate(const EvaluationOrder& evalOrder, int subnetTime, + EvalContext* context = nullptr) { + for (const auto& var : evalOrder) { + int timestamp = context == nullptr ? var->timestamp : context->at(var).timestamp; + // If we find a node that has been modified since last evaluation, the subnet needs to be + // re-evaluated. + if (timestamp > subnetTime) return true; + } + return false; +} + +// Helper function to evaluate the subnet recursively. +// Iterate through all combinations of FREE RandomVariables choices. +static void evalSubnetHelper(const EvaluationOrder& evalOrder, EvalContext* context, size_t i = 0) { + if (i == evalOrder.size()) { + // Reach the end of the evaluation, find a valid combination. + for (auto& var : evalOrder) context->at(var).stage(); + return; + } + const auto& var = evalOrder[i]; + if (var->type == RandomVariableType::FREE) { + // For FREE RandomVariable, iterate through all valid choices. + for (int val : context->at(var).committed) { + var->value = val; + evalSubnetHelper(evalOrder, context, i + 1); + } + return; + } else if (var->type == RandomVariableType::OP) { + // For OP RandomVariable, evaluate from parents and terminate if the result is invalid. + if (!context->at(var).eval()) return; + } + evalSubnetHelper(evalOrder, context, i + 1); +} + +// Check if the subnet has only one single OP RandomVariable. +static inline bool isSingleOpSubnet(const EvaluationOrder& evalOrder) { + int numOp = 0; + for (const auto& var : evalOrder) { + if (var->type == RandomVariableType::OP) numOp++; + if (numOp > 1) return false; + } + return numOp != 0; +} + +// Evaluate with a potentially faster approach provided by IRandomVariableOp. +static inline void evalSubnetSingleOpHelper(const EvaluationOrder& evalOrder, + EvalContext* context) { + NN_FUZZER_LOG << "Identified as single op subnet"; + const auto& var = evalOrder.back(); + NN_FUZZER_CHECK(var->type == RandomVariableType::OP); + var->op->eval(&context->at(var->parent1).committed, + var->parent2 == nullptr ? nullptr : &context->at(var->parent2).committed, + &context->at(var).committed, &context->at(var->parent1).staging, + var->parent2 == nullptr ? nullptr : &context->at(var->parent2).staging, + &context->at(var).staging); +} + +// Check if the number of combinations of FREE RandomVariables exceeds the limit. +static inline uint64_t getNumCombinations(const EvaluationOrder& evalOrder, + EvalContext* context = nullptr) { + constexpr uint64_t kLimit = 1e8; + uint64_t numCombinations = 1; + for (const auto& var : evalOrder) { + if (var->type == RandomVariableType::FREE) { + size_t size = + context == nullptr ? var->range.size() : context->at(var).committed.size(); + numCombinations *= size; + // To prevent overflow. + if (numCombinations > kLimit) return kLimit; + } + } + return numCombinations; +} + +// Evaluate the subnet recursively. Will return fail if the number of combinations of FREE +// RandomVariable exceeds the threshold kMaxNumCombinations. +static bool evalSubnetWithBruteForce(const EvaluationOrder& evalOrder, EvalContext* context) { + constexpr uint64_t kMaxNumCombinations = 1e7; + NN_FUZZER_LOG << "Evaluate with brute force"; + if (isSingleOpSubnet(evalOrder)) { + // If the network only have one single OP, dispatch to a faster evaluation. + evalSubnetSingleOpHelper(evalOrder, context); + } else { + if (getNumCombinations(evalOrder, context) > kMaxNumCombinations) { + NN_FUZZER_LOG << "Terminate the evaluation because of large search range"; + std::cout << "[ ] Terminate the evaluation because of large search range" + << std::endl; + return false; + } + evalSubnetHelper(evalOrder, context); + } + for (auto& var : evalOrder) { + if (context->at(var).staging.empty()) { + NN_FUZZER_LOG << "Evaluation failed at " << toString(var, context); + return false; + } + context->at(var).commit(); + } + return true; +} + +struct LocalNetwork { + EvaluationOrder evalOrder; + std::vector<RandomVariableNode> bridgeNodes; + int timestamp = 0; + + bool eval(EvalContext* context) { + NN_FUZZER_LOG << "Evaluate local network with timestamp = " << timestamp; + // Temporarily treat bridge nodes as FREE RandomVariables. + for (const auto& var : bridgeNodes) { + context->at(var).originalType = var->type; + var->type = RandomVariableType::FREE; + } + for (const auto& var : evalOrder) { + context->at(var).staging.clear(); + NN_FUZZER_LOG << " - " << toString(var, context); + } + bool success = evalSubnetWithBruteForce(evalOrder, context); + // Reset the RandomVariable types for bridge nodes. + for (const auto& var : bridgeNodes) var->type = context->at(var).originalType; + return success; + } +}; + +// Partition the network further into LocalNetworks based on the result from bridge annotation +// algorithm. +class GraphPartitioner : public DisjointNetwork { + public: + GraphPartitioner() = default; + + std::vector<LocalNetwork> partition(const EvaluationOrder& evalOrder, int timestamp) { + annotateBridge(evalOrder); + for (const auto& var : evalOrder) add(var); + return get(timestamp); + } + + private: + GraphPartitioner(const GraphPartitioner&) = delete; + GraphPartitioner& operator=(const GraphPartitioner&) = delete; + + // Find the parent-child relationship between var1 and var2, and reset the bridge. + void setBridgeFlag(const RandomVariableNode& var1, const RandomVariableNode& var2) { + if (var1->parent1 == var2) { + mBridgeInfo[var1].isParent1Bridge = true; + } else if (var1->parent2 == var2) { + mBridgeInfo[var1].isParent2Bridge = true; + } else { + setBridgeFlag(var2, var1); + } + } + + // Annoate the bridges with DFS -- an edge [u, v] is a bridge if none of u's ancestor is + // reachable from a node in the subtree of b. The complexity is O(V + E). + // discoveryTime: The timestamp a node is visited + // lowTime: The min discovery time of all reachable nodes from the subtree of the node. + void annotateBridgeHelper(const RandomVariableNode& var, int* time) { + mBridgeInfo[var].visited = true; + mBridgeInfo[var].discoveryTime = mBridgeInfo[var].lowTime = (*time)++; + + // The algorithm operates on undirected graph. First find all adjacent nodes. + auto adj = var->children; + if (var->parent1 != nullptr) adj.push_back(var->parent1); + if (var->parent2 != nullptr) adj.push_back(var->parent2); + + for (const auto& weakChild : adj) { + auto child = weakChild.lock(); + NN_FUZZER_CHECK(child != nullptr); + if (mBridgeInfo.find(child) == mBridgeInfo.end()) continue; + if (!mBridgeInfo[child].visited) { + mBridgeInfo[child].parent = var; + annotateBridgeHelper(child, time); + + // If none of nodes in the subtree of child is connected to any ancestors of var, + // then it is a bridge. + mBridgeInfo[var].lowTime = + std::min(mBridgeInfo[var].lowTime, mBridgeInfo[child].lowTime); + if (mBridgeInfo[child].lowTime > mBridgeInfo[var].discoveryTime) + setBridgeFlag(var, child); + } else if (mBridgeInfo[var].parent != child) { + mBridgeInfo[var].lowTime = + std::min(mBridgeInfo[var].lowTime, mBridgeInfo[child].discoveryTime); + } + } + } + + // Find all bridges in the subnet with DFS. + void annotateBridge(const EvaluationOrder& evalOrder) { + for (const auto& var : evalOrder) mBridgeInfo[var]; + int time = 0; + for (const auto& var : evalOrder) { + if (!mBridgeInfo[var].visited) annotateBridgeHelper(var, &time); + } + } + + // Re-partition the network by treating bridges as no edge. + void add(const RandomVariableNode& var) { + auto parent1 = var->parent1; + auto parent2 = var->parent2; + if (mBridgeInfo[var].isParent1Bridge) var->parent1 = nullptr; + if (mBridgeInfo[var].isParent2Bridge) var->parent2 = nullptr; + DisjointNetwork::add(var); + var->parent1 = parent1; + var->parent2 = parent2; + } + + // Add bridge nodes to the local network and remove single node subnet. + std::vector<LocalNetwork> get(int timestamp) { + std::vector<LocalNetwork> res; + for (auto& pair : mEvalOrderMap) { + // We do not need to evaluate subnet with only a single node. + if (pair.second.size() == 1 && pair.second[0]->parent1 == nullptr) continue; + res.emplace_back(); + for (const auto& var : pair.second) { + if (mBridgeInfo[var].isParent1Bridge) { + res.back().evalOrder.push_back(var->parent1); + res.back().bridgeNodes.push_back(var->parent1); + } + if (mBridgeInfo[var].isParent2Bridge) { + res.back().evalOrder.push_back(var->parent2); + res.back().bridgeNodes.push_back(var->parent2); + } + res.back().evalOrder.push_back(var); + } + res.back().timestamp = timestamp; + } + return res; + } + + // For bridge discovery algorithm. + struct BridgeInfo { + bool isParent1Bridge = false; + bool isParent2Bridge = false; + int discoveryTime = 0; + int lowTime = 0; + bool visited = false; + std::shared_ptr<RandomVariableBase> parent = nullptr; + }; + std::unordered_map<RandomVariableNode, BridgeInfo> mBridgeInfo; +}; + +// Evaluate subnets repeatedly until converge. +// Class T_Subnet must have member evalOrder, timestamp, and member function eval. +template <class T_Subnet> +inline bool evalSubnetsRepeatedly(std::vector<T_Subnet>* subnets, EvalContext* context) { + bool terminate = false; + while (!terminate) { + terminate = true; + for (auto& subnet : *subnets) { + if (needEvaluate(subnet.evalOrder, subnet.timestamp, context)) { + if (!subnet.eval(context)) return false; + subnet.timestamp = RandomVariableNetwork::get()->getGlobalTime(); + terminate = false; + } + } + } + return true; +} + +// Evaluate the subnet by first partitioning it further into LocalNetworks. +static bool evalSubnetWithLocalNetwork(const EvaluationOrder& evalOrder, int timestamp, + EvalContext* context) { + NN_FUZZER_LOG << "Evaluate with local network"; + auto localNetworks = GraphPartitioner().partition(evalOrder, timestamp); + return evalSubnetsRepeatedly(&localNetworks, context); +} + +struct LeafNetwork { + EvaluationOrder evalOrder; + int timestamp = 0; + LeafNetwork(const RandomVariableNode& var, int timestamp) : timestamp(timestamp) { + std::set<RandomVariableNode> visited; + constructorHelper(var, &visited); + } + // Construct the leaf network by recursively including parent nodes. + void constructorHelper(const RandomVariableNode& var, std::set<RandomVariableNode>* visited) { + if (var == nullptr || visited->find(var) != visited->end()) return; + constructorHelper(var->parent1, visited); + constructorHelper(var->parent2, visited); + visited->insert(var); + evalOrder.push_back(var); + } + bool eval(EvalContext* context) { + return evalSubnetWithLocalNetwork(evalOrder, timestamp, context); + } +}; + +// Evaluate the subnet by leaf network. +// NOTE: This algorithm will only produce correct result for *most* of the time (> 99%). +// The random graph generator is expected to retry if it fails. +static bool evalSubnetWithLeafNetwork(const EvaluationOrder& evalOrder, int timestamp, + EvalContext* context) { + NN_FUZZER_LOG << "Evaluate with leaf network"; + // Construct leaf networks. + std::vector<LeafNetwork> leafNetworks; + for (const auto& var : evalOrder) { + if (var->children.empty()) { + NN_FUZZER_LOG << "Found leaf " << toString(var, context); + leafNetworks.emplace_back(var, timestamp); + } + } + return evalSubnetsRepeatedly(&leafNetworks, context); +} + +void RandomVariableNetwork::addDimensionProd(const std::vector<RandomVariable>& dims) { + if (dims.size() <= 1) return; + EvaluationOrder order; + for (const auto& dim : dims) order.push_back(dim.get()); + mDimProd.push_back(order); +} + +bool enforceDimProd(const std::vector<EvaluationOrder>& mDimProd, + const std::unordered_map<RandomVariableNode, int>& indexMap, + EvalContext* context, std::set<int>* dirtySubnets) { + for (auto& evalOrder : mDimProd) { + NN_FUZZER_LOG << " Dimension product network size = " << evalOrder.size(); + // Initialize EvalInfo of each RandomVariable. + for (auto& var : evalOrder) { + if (context->find(var) == context->end()) context->emplace(var, var); + NN_FUZZER_LOG << " - " << toString(var, context); + } + + // Enforce the product of the dimension values below kMaxValue: + // max(dimA) = kMaxValue / (min(dimB) * min(dimC) * ...) + int prod = 1; + for (const auto& var : evalOrder) prod *= (*context->at(var).committed.begin()); + for (auto& var : evalOrder) { + auto& committed = context->at(var).committed; + int maxValue = kMaxValue / (prod / *committed.begin()); + auto it = committed.upper_bound(maxValue); + // var has empty range -> no solution. + if (it == committed.begin()) return false; + // The range is not modified -> continue. + if (it == committed.end()) continue; + // The range is modified -> the subnet of var is dirty, i.e. needs re-evaluation. + committed.erase(it, committed.end()); + context->at(var).timestamp = RandomVariableNetwork::get()->getGlobalTime(); + dirtySubnets->insert(indexMap.at(var)); + } + } + return true; +} + +bool RandomVariableNetwork::evalRange() { + constexpr uint64_t kMaxNumCombinationsWithBruteForce = 500; + constexpr uint64_t kMaxNumCombinationsWithLocalNetwork = 1e5; + NN_FUZZER_LOG << "Evaluate on " << mEvalOrderMap.size() << " sub-networks"; + EvalContext context; + std::set<int> dirtySubnets; // Which subnets needs evaluation. + for (auto& pair : mEvalOrderMap) { + const auto& evalOrder = pair.second; + // Decide whether needs evaluation by timestamp -- if no range has changed after the last + // evaluation, then the subnet does not need re-evaluation. + if (evalOrder.size() == 1 || !needEvaluate(evalOrder, mTimestamp)) continue; + dirtySubnets.insert(pair.first); + } + if (!enforceDimProd(mDimProd, mIndexMap, &context, &dirtySubnets)) return false; + + // Repeat until the ranges converge. + while (!dirtySubnets.empty()) { + for (int ind : dirtySubnets) { + const auto& evalOrder = mEvalOrderMap[ind]; + NN_FUZZER_LOG << " Sub-network #" << ind << " size = " << evalOrder.size(); + + // Initialize EvalInfo of each RandomVariable. + for (auto& var : evalOrder) { + if (context.find(var) == context.end()) context.emplace(var, var); + NN_FUZZER_LOG << " - " << toString(var, &context); + } + + // Dispatch to different algorithm according to search range. + bool success; + uint64_t numCombinations = getNumCombinations(evalOrder); + if (numCombinations <= kMaxNumCombinationsWithBruteForce) { + success = evalSubnetWithBruteForce(evalOrder, &context); + } else if (numCombinations <= kMaxNumCombinationsWithLocalNetwork) { + success = evalSubnetWithLocalNetwork(evalOrder, mTimestamp, &context); + } else { + success = evalSubnetWithLeafNetwork(evalOrder, mTimestamp, &context); + } + if (!success) return false; + } + dirtySubnets.clear(); + if (!enforceDimProd(mDimProd, mIndexMap, &context, &dirtySubnets)) return false; + } + // A successful evaluation, update RandomVariables from EvalContext. + for (auto& pair : context) pair.second.updateRange(); + mTimestamp = getGlobalTime(); + NN_FUZZER_LOG << "Finish range evaluation"; + return true; +} + +static void unsetEqual(const RandomVariableNode& node) { + if (node == nullptr) return; + NN_FUZZER_LOG << "Unset equality of var" << node->index; + auto weakPtrEqual = [&node](const std::weak_ptr<RandomVariableBase>& ptr) { + return ptr.lock() == node; + }; + RandomVariableNode parent1 = node->parent1, parent2 = node->parent2; + parent1->children.erase( + std::find_if(parent1->children.begin(), parent1->children.end(), weakPtrEqual)); + node->parent1 = nullptr; + if (parent2 != nullptr) { + // For Equal. + parent2->children.erase( + std::find_if(parent2->children.begin(), parent2->children.end(), weakPtrEqual)); + node->parent2 = nullptr; + } else { + // For UnaryEqual. + node->type = RandomVariableType::FREE; + node->op = nullptr; + } +} + +// A class to revert all the changes made to RandomVariableNetwork since the Reverter object is +// constructed. Only used when setEqualIfCompatible results in incompatible. +class RandomVariableNetwork::Reverter { + public: + // Take a snapshot of RandomVariableNetwork when Reverter is constructed. + Reverter() : mSnapshot(*RandomVariableNetwork::get()) {} + // Add constraint (Equal) nodes to the reverter. + void addNode(const RandomVariableNode& node) { mEqualNodes.push_back(node); } + void revert() { + NN_FUZZER_LOG << "Revert RandomVariableNetwork"; + // Release the constraints. + for (const auto& node : mEqualNodes) unsetEqual(node); + // Reset all member variables. + *RandomVariableNetwork::get() = std::move(mSnapshot); + } + + private: + Reverter(const Reverter&) = delete; + Reverter& operator=(const Reverter&) = delete; + RandomVariableNetwork mSnapshot; + std::vector<RandomVariableNode> mEqualNodes; +}; + +bool RandomVariableNetwork::setEqualIfCompatible(const std::vector<RandomVariable>& lhs, + const std::vector<RandomVariable>& rhs) { + NN_FUZZER_LOG << "Check compatibility of {" << joinStr(", ", lhs) << "} and {" + << joinStr(", ", rhs) << "}"; + if (lhs.size() != rhs.size()) return false; + Reverter reverter; + bool result = true; + for (size_t i = 0; i < lhs.size(); i++) { + auto node = lhs[i].setEqual(rhs[i]).get(); + reverter.addNode(node); + // Early terminate if there is no common choice between two ranges. + if (node != nullptr && node->range.empty()) result = false; + } + result = result && evalRange(); + if (!result) reverter.revert(); + NN_FUZZER_LOG << "setEqualIfCompatible: " << (result ? "[COMPATIBLE]" : "[INCOMPATIBLE]"); + return result; +} + +bool RandomVariableNetwork::freeze() { + NN_FUZZER_LOG << "Freeze the random network"; + if (!evalRange()) return false; + + std::vector<RandomVariableNode> nodes; + for (const auto& pair : mEvalOrderMap) { + // Find all FREE RandomVariables in the subnet. + for (const auto& var : pair.second) { + if (var->type == RandomVariableType::FREE) nodes.push_back(var); + } + } + + // Randomly shuffle the order, this is for a more uniform randomness. + randomShuffle(&nodes); + + // An inefficient algorithm that does freeze -> re-evaluate for every FREE RandomVariable. + // TODO: Might be able to optimize this. + for (const auto& var : nodes) { + if (var->type != RandomVariableType::FREE) continue; + size_t size = var->range.size(); + NN_FUZZER_LOG << "Freeze " << var; + var->freeze(); + NN_FUZZER_LOG << " " << var; + // There is no need to re-evaluate if the FREE RandomVariable have only one choice. + if (size > 1) { + var->updateTimestamp(); + if (!evalRange()) { + NN_FUZZER_LOG << "Freeze failed at " << var; + return false; + } + } + } + NN_FUZZER_LOG << "Finish freezing the random network"; + return true; +} + +} // namespace fuzzing_test +} // namespace nn +} // namespace android diff --git a/nn/runtime/test/fuzzing/TestRandomGraph.cpp b/nn/runtime/test/fuzzing/TestRandomGraph.cpp index 2047cbe04..6e71652a9 100644 --- a/nn/runtime/test/fuzzing/TestRandomGraph.cpp +++ b/nn/runtime/test/fuzzing/TestRandomGraph.cpp @@ -41,7 +41,6 @@ #include "SampleDriverFull.h" using android::nn::sample_driver::SampleDriverFull; -using namespace android::nn::hal; #endif @@ -66,27 +65,27 @@ class TestDriverV1_1 : public V1_1::IDevice { TestDriverV1_1() : mDriverV1_2(new SampleDriverFull(name, {.execTime = 0.8f, .powerUsage = 0.8f})) {} static constexpr char name[] = "TestDriverV1_1"; - Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { + hardware::Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override { return mDriverV1_2->getCapabilities_1_1(_hidl_cb); } - Return<void> getSupportedOperations_1_1(const V1_1::Model& model, - getSupportedOperations_1_1_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations_1_1( + const V1_1::Model& model, getSupportedOperations_1_1_cb _hidl_cb) override { return mDriverV1_2->getSupportedOperations_1_1(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel_1_1( - const V1_1::Model& model, ExecutionPreference preference, + hardware::Return<V1_0::ErrorStatus> prepareModel_1_1( + const V1_1::Model& model, V1_1::ExecutionPreference preference, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mDriverV1_2->prepareModel_1_1(model, preference, actualCallback); } - Return<DeviceStatus> getStatus() override { return mDriverV1_2->getStatus(); } - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mDriverV1_2->getStatus(); } + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mDriverV1_2->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mDriverV1_2->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mDriverV1_2->prepareModel(model, actualCallback); @@ -102,19 +101,19 @@ class TestDriverV1_0 : public V1_0::IDevice { TestDriverV1_0() : mDriverV1_2(new SampleDriverFull(name, {.execTime = 0.7f, .powerUsage = 0.7f})) {} static constexpr char name[] = "TestDriverV1_0"; - Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { + hardware::Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override { return mDriverV1_2->getCapabilities(_hidl_cb); } - Return<void> getSupportedOperations(const V1_0::Model& model, - getSupportedOperations_cb _hidl_cb) override { + hardware::Return<void> getSupportedOperations(const V1_0::Model& model, + getSupportedOperations_cb _hidl_cb) override { return mDriverV1_2->getSupportedOperations(model, _hidl_cb); } - Return<V1_0::ErrorStatus> prepareModel( + hardware::Return<V1_0::ErrorStatus> prepareModel( const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& actualCallback) override { return mDriverV1_2->prepareModel(model, actualCallback); } - Return<DeviceStatus> getStatus() override { return mDriverV1_2->getStatus(); } + hardware::Return<V1_0::DeviceStatus> getStatus() override { return mDriverV1_2->getStatus(); } private: const sp<V1_2::IDevice> mDriverV1_2; diff --git a/nn/runtime/test/fuzzing/operation_signatures/OperationSignatureUtils.h b/nn/runtime/test/fuzzing/operation_signatures/OperationSignatureUtils.h index 8fa93327f..53b5aad17 100644 --- a/nn/runtime/test/fuzzing/operation_signatures/OperationSignatureUtils.h +++ b/nn/runtime/test/fuzzing/operation_signatures/OperationSignatureUtils.h @@ -310,7 +310,7 @@ inline void defaultScalarOperandConstructor(TestOperandType dataType, uint32_t, op->zeroPoint = 0; break; default: - NN_FUZZER_CHECK(false) << "Data type " << toString(dataType) + NN_FUZZER_CHECK(false) << "Data type " << dataType << " is not supported in defaultScalarOperandConstructor."; } } diff --git a/nn/tools/test_generator/test_harness/TestHarness.cpp b/nn/tools/test_generator/test_harness/TestHarness.cpp index 56e1414fe..841eebfff 100644 --- a/nn/tools/test_generator/test_harness/TestHarness.cpp +++ b/nn/tools/test_generator/test_harness/TestHarness.cpp @@ -558,12 +558,12 @@ void dumpTestBufferToSpecFileHelper(const TestBuffer& buffer, bool useHexFloat, } // namespace -const char* toString(TestOperandType type) { - return kOperandTypeNames[static_cast<int>(type)]; +std::ostream& operator<<(std::ostream& os, const TestOperandType& type) { + return os << kOperandTypeNames[static_cast<int>(type)]; } -const char* toString(TestOperationType type) { - return kOperationTypeNames[static_cast<int>(type)]; +std::ostream& operator<<(std::ostream& os, const TestOperationType& type) { + return os << kOperationTypeNames[static_cast<int>(type)]; } // Dump a test buffer. @@ -605,7 +605,7 @@ void SpecDumper::dumpTestBuffer(TestOperandType type, const TestBuffer& buffer, void SpecDumper::dumpTestOperand(const TestOperand& operand, uint32_t index) { mOs << "op" << index << " = " << getOperandClassInSpecFile(operand.lifetime) << "(\"op" << index - << "\", [\"" << toString(operand.type) << "\", [" + << "\", [\"" << operand.type << "\", [" << join(", ", operand.dimensions, defaultToStringFunc<uint32_t>) << "]"; if (operand.scale != 0.0f || operand.zeroPoint != 0) { mOs << ", float.fromhex(" << toHexFloatString(operand.scale) << "), " << operand.zeroPoint; @@ -635,7 +635,7 @@ void SpecDumper::dumpTestOperand(const TestOperand& operand, uint32_t index) { void SpecDumper::dumpTestOperation(const TestOperation& operation) { auto toOperandName = [](uint32_t index) { return "op" + std::to_string(index); }; - mOs << "model = model.Operation(\"" << toString(operation.type) << "\", " + mOs << "model = model.Operation(\"" << operation.type << "\", " << join(", ", operation.inputs, toOperandName) << ").To(" << join(", ", operation.outputs, toOperandName) << ")\n"; } diff --git a/nn/tools/test_generator/test_harness/include/TestHarness.h b/nn/tools/test_generator/test_harness/include/TestHarness.h index 0a7dce81d..be4f5625a 100644 --- a/nn/tools/test_generator/test_harness/include/TestHarness.h +++ b/nn/tools/test_generator/test_harness/include/TestHarness.h @@ -508,8 +508,8 @@ bool isQuantizedType(TestOperandType type); TestModel convertQuant8AsymmOperandsToSigned(const TestModel& testModel); -const char* toString(TestOperandType type); -const char* toString(TestOperationType type); +std::ostream& operator<<(std::ostream& os, const TestOperandType& type); +std::ostream& operator<<(std::ostream& os, const TestOperationType& type); // Dump a test model in the format of a spec file for debugging and visualization purpose. class SpecDumper { |