You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

407 lines
20 KiB

/*
* 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.
*/
// This file contains pre-canonical-types utility code and includes HAL
// utilities. LegacyUtils.h is the subset of these utilities that do not touch
// HAL.
#ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_LEGACY_HAL_UTILS_H
#define ANDROID_FRAMEWORKS_ML_NN_COMMON_LEGACY_HAL_UTILS_H
#include <android-base/logging.h>
#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "HalInterfaces.h"
#include "LegacyUtils.h"
#include "NeuralNetworks.h"
#include "ValidateHal.h"
namespace android {
namespace nn {
using LegacyClock = std::chrono::steady_clock;
using LegacyDuration = std::chrono::duration<uint64_t, std::nano>;
using LegacyOptionalDuration = std::optional<LegacyDuration>;
using LegacyTimePoint = std::chrono::time_point<std::chrono::steady_clock, LegacyDuration>;
using LegacyOptionalTimePoint = std::optional<LegacyTimePoint>;
// Make an optional deadline from an V1_3::OptionalTimePoint.
LegacyOptionalTimePoint makeDeadline(const V1_3::OptionalTimePoint& timePoint);
// Make an optional deadline from an V1_3::OptionalDuration.
LegacyOptionalTimePoint makeDeadline(const V1_3::OptionalTimeoutDuration& optionalDuration);
// Returns true if the deadline has passed. Returns false if either the deadline
// has not been exceeded or if the deadline is not present.
bool hasDeadlinePassed(const LegacyOptionalTimePoint& deadline);
// Ensure that every user of FalseyErrorStream is linked to the
// correct instance, using the correct LOG_TAG
namespace {
template <HalVersion version>
struct VersionedType {};
template <>
struct VersionedType<HalVersion::V1_2> {
using OperandPerformance = V1_2::Capabilities::OperandPerformance;
using OperandType = V1_2::OperandType;
};
template <>
struct VersionedType<HalVersion::V1_3> {
using OperandPerformance = V1_3::Capabilities::OperandPerformance;
using OperandType = V1_3::OperandType;
};
template <HalVersion version>
using VersionedOperandPerformance = typename VersionedType<version>::OperandPerformance;
template <HalVersion version>
using VersionedOperandType = typename VersionedType<version>::OperandType;
} // namespace
// Return a vector with one entry for each non-extension OperandType except
// SUBGRAPH, set to the specified PerformanceInfo value. The vector will be
// sorted by OperandType.
//
// Control flow (OperandType::SUBGRAPH) operation performance is specified
// separately using Capabilities::ifPerformance and
// Capabilities::whilePerformance.
template <HalVersion version>
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(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.
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(V1_3::OperandType type);
// Returns true if an operation type is an extension 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
// unspecified dimension, returns zero.
//
// Aborts if the specified type is an extension type.
// Aborts if the size would overflow the return type.
//
// See also TypeManager::getSizeOfData(OperandType, const std::vector<uint32_t>&).
uint32_t nonExtensionOperandSizeOfData(V1_3::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
// unspecified dimension, returns zero.
//
// Aborts if the specified type is an extension type.
// Aborts if the size would overflow the return type.
//
// See also TypeManager::getSizeOfData(const Operand&).
inline uint32_t nonExtensionOperandSizeOfData(const V1_3::Operand& operand) {
return nonExtensionOperandSizeOfData(operand.type, operand.dimensions);
}
// Returns true if the amount of space needed to store a value of the specified
// dimensions and element size overflows the uint32_t type.
//
// Aborts if the specified type is an extension type.
//
// See also TypeManager::sizeOfDataOverflowsUInt32(OperandType, const std::vector<uint32_t>&).
bool nonExtensionOperandSizeOfDataOverflowsUInt32(V1_3::OperandType type,
const std::vector<uint32_t>& dimensions);
// Returns the name of the operation type in ASCII.
std::string getOperationName(V1_3::OperationType opCode);
// Returns the name of the operand type in ASCII.
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(V1_3::OperandType type,
const std::vector<uint32_t>& dimensions);
bool tensorHasUnspecifiedDimensions(const V1_3::Operand& operand);
// Does a detailed LOG(INFO) of the 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);
bool validateOperandSymmPerChannelQuantParams(
const V1_3::Operand& halOperand,
const ANeuralNetworksSymmPerChannelQuantParams& channelQuant, const char* tag);
// Convert ANEURALNETWORKS_* result code to ErrorStatus.
// Not guaranteed to be a 1-to-1 mapping.
V1_3::ErrorStatus convertResultCodeToHalErrorStatus(int resultCode);
// Convert ErrorStatus to ANEURALNETWORKS_* result code.
// Not guaranteed to be a 1-to-1 mapping.
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<OutputShape>, Timing> getExecutionResult(
V1_3::ErrorStatus status, const hardware::hidl_vec<V1_2::OutputShape>& outputShapes,
const V1_2::Timing& timing);
// Forward declaration for type defined in CpuExecutor.h.
class RunTimePoolInfo;
bool setRunTimePoolInfosFromHidlMemories(std::vector<RunTimePoolInfo>* poolInfos,
const hardware::hidl_vec<hardware::hidl_memory>& pools);
// Versioning
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()
// postcondition: *noncompliantOperations consists of the indices of the noncompliant
// 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 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 V1_3::Model& model,
std::set<uint32_t>* noncompliantOperations = nullptr);
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 V1_3::Model& model,
std::set<uint32_t>* noncompliantOperations = nullptr);
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 V1_3::Model& model,
std::set<uint32_t>* noncompliantOperations = nullptr);
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 {};
}
// 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);
SharedMemory 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);
OptionalDuration 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<SharedMemory> 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 SharedMemory& memory);
hardware::hidl_vec<hardware::hidl_memory> convertToV1_0(const std::vector<SharedMemory>& 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 OptionalDuration& 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
#endif // ANDROID_FRAMEWORKS_ML_NN_COMMON_LEGACY_HAL_UTILS_H