diff options
author | Slava Shklyaev <slavash@google.com> | 2020-11-02 20:00:18 +0000 |
---|---|---|
committer | Slava Shklyaev <slavash@google.com> | 2020-11-20 13:56:52 +0000 |
commit | 083da328b8899ce08f63fc564db444669f62b324 (patch) | |
tree | 393400e347cac5b974dddc0b93060aef51e2317e | |
parent | 72737fc910d8a0f3f96d08bc2eb861551cb84e41 (diff) | |
download | ml-083da328b8899ce08f63fc564db444669f62b324.tar.gz |
Replace native_handle with unique_fd
This change replaces native_handle_t from libutils with a custom type
that wraps std::vector<base::unique_fd> and std::vector<int>.
Bug: 160669116
Test: NNT_static
Change-Id: If4d767b35c2d48cabcb6a9a3436079f6f7d39a13
Merged-In: If4d767b35c2d48cabcb6a9a3436079f6f7d39a13
(cherry picked from commit b3c5d46cd1a7e8c7f4c624d2c24bf721f4d0edb2)
-rw-r--r-- | nn/common/SharedMemoryAndroid.cpp | 124 | ||||
-rw-r--r-- | nn/common/SharedMemoryHost.cpp | 57 | ||||
-rw-r--r-- | nn/common/TypeUtils.cpp | 2 | ||||
-rw-r--r-- | nn/common/Types.cpp | 32 | ||||
-rw-r--r-- | nn/common/Validation.cpp | 14 | ||||
-rw-r--r-- | nn/common/include/nnapi/IDevice.h | 8 | ||||
-rw-r--r-- | nn/common/include/nnapi/TypeUtils.h | 2 | ||||
-rw-r--r-- | nn/common/include/nnapi/Types.h | 23 | ||||
-rw-r--r-- | nn/common/include/nnapi/Validation.h | 4 | ||||
-rw-r--r-- | nn/runtime/Manager.cpp | 34 | ||||
-rw-r--r-- | nn/runtime/VersionedInterfaces.cpp | 67 | ||||
-rw-r--r-- | nn/runtime/VersionedInterfaces.h | 14 | ||||
-rw-r--r-- | nn/runtime/test/TestVersionedInterfaces.cpp | 24 |
13 files changed, 232 insertions, 173 deletions
diff --git a/nn/common/SharedMemoryAndroid.cpp b/nn/common/SharedMemoryAndroid.cpp index 9baca73c5..18881e04a 100644 --- a/nn/common/SharedMemoryAndroid.cpp +++ b/nn/common/SharedMemoryAndroid.cpp @@ -19,12 +19,12 @@ #include <android-base/scopeguard.h> #include <android/hardware_buffer.h> #include <android/hidl/allocator/1.0/IAllocator.h> -#include <cutils/native_handle.h> #include <hidl/HidlSupport.h> #include <hidlmemory/mapping.h> #include <sys/mman.h> #include <vndk/hardware_buffer.h> +#include <algorithm> #include <any> #include <limits> #include <memory> @@ -66,28 +66,74 @@ GeneralResult<hidl_memory> allocateSharedMemory(size_t size) { return maybeMemory; } -Memory createMemory(const hidl_memory& memory) { - CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max()); +GeneralResult<hardware::hidl_handle> hidlHandleFromSharedHandle(const SharedHandle& handle) { + if (handle == nullptr) { + return {}; + } - auto* cloned = native_handle_clone(memory.handle()); - auto nativeHandle = ::android::NativeHandle::create(cloned, /*ownsHandle=*/true); + std::vector<base::unique_fd> fds; + fds.reserve(handle->fds.size()); + for (const auto& fd : handle->fds) { + int dupFd = dup(fd); + if (dupFd == -1) { + return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd"; + } + fds.emplace_back(dupFd); + } - return { - .handle = std::move(nativeHandle), + native_handle_t* nativeHandle = native_handle_create(handle->fds.size(), handle->ints.size()); + if (nativeHandle == nullptr) { + return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle"; + } + for (size_t i = 0; i < fds.size(); ++i) { + nativeHandle->data[i] = fds[i].release(); + } + std::copy(handle->ints.begin(), handle->ints.end(), &nativeHandle->data[nativeHandle->numFds]); + + hardware::hidl_handle hidlHandle; + hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true); + return hidlHandle; +} + +GeneralResult<SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle) { + if (handle == nullptr) { + return nullptr; + } + + std::vector<base::unique_fd> fds; + fds.reserve(handle->numFds); + for (int i = 0; i < handle->numFds; ++i) { + int dupFd = dup(handle->data[i]); + if (dupFd == -1) { + return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd"; + } + fds.emplace_back(dupFd); + } + + std::vector<int> ints(&handle->data[handle->numFds], + &handle->data[handle->numFds + handle->numInts]); + + return std::make_shared<const Handle>(Handle{ + .fds = std::move(fds), + .ints = std::move(ints), + }); +} + +GeneralResult<Memory> createMemory(const hidl_memory& memory) { + CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max()); + return Memory{ + .handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())), .size = static_cast<uint32_t>(memory.size()), .name = memory.name(), }; } -hidl_memory createHidlMemory(const Memory& memory) { - const auto hidlMemory = hidl_memory(memory.name, memory.handle->handle(), memory.size); - // Copy memory to force the native_handle_t to be copied. - auto copiedMemory = hidlMemory; - return copiedMemory; +GeneralResult<hidl_memory> createHidlMemory(const Memory& memory) { + return hidl_memory(memory.name, NN_TRY(hidlHandleFromSharedHandle(memory.handle)), memory.size); } GeneralResult<Mapping> mapAshmem(const Memory& memory) { - const auto hidlMemory = createHidlMemory(memory); + const auto hidlMemory = NN_TRY(createHidlMemory(memory)); const auto mapping = mapMemory(hidlMemory); if (mapping == nullptr) { return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to map memory"; @@ -116,10 +162,10 @@ struct MmapFdMappingContext { GeneralResult<Mapping> mapMemFd(const Memory& memory) { const size_t size = memory.size; - const native_handle_t* handle = memory.handle->handle(); - const int fd = handle->data[0]; - const int prot = handle->data[1]; - const size_t offset = getOffsetFromInts(handle->data[2], handle->data[3]); + const SharedHandle& handle = memory.handle; + const int fd = handle->fds[0]; + const int prot = handle->ints[0]; + const size_t offset = getOffsetFromInts(handle->ints[1], handle->ints[2]); std::shared_ptr<base::MappedFile> mapping = base::MappedFile::FromFd(fd, offset, size, prot); if (mapping == nullptr) { @@ -132,7 +178,7 @@ GeneralResult<Mapping> mapMemFd(const Memory& memory) { } GeneralResult<Mapping> mapAhwbBlobMemory(const Memory& memory) { - const auto* handle = memory.handle->handle(); + const SharedHandle& handle = memory.handle; const auto size = memory.size; const auto format = AHARDWAREBUFFER_FORMAT_BLOB; const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; @@ -152,7 +198,8 @@ GeneralResult<Mapping> mapAhwbBlobMemory(const Memory& memory) { AHardwareBuffer* hardwareBuffer = nullptr; status_t status = AHardwareBuffer_createFromHandle( - &desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &hardwareBuffer); + &desc, NN_TRY(hidlHandleFromSharedHandle(handle)), + AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &hardwareBuffer); if (status != NO_ERROR) { return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Can't create AHardwareBuffer from handle. Error: " << status; @@ -196,31 +243,23 @@ GeneralResult<Memory> createSharedMemoryFromFd(size_t size, int prot, int fd, si } // Duplicate the file descriptor so the resultant Memory owns its own version. - int dupfd = dup(fd); - if (dupfd == -1) { + int dupFd = dup(fd); + if (dupFd == -1) { // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here? return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << "Failed to dup the fd"; } - // Create a temporary native handle to own the dupfd. - native_handle_t* nativeHandle = native_handle_create(1, 3); - if (nativeHandle == nullptr) { - close(dupfd); - // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here? - return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle"; - } + std::vector<base::unique_fd> fds; + fds.emplace_back(dupFd); const auto [lowOffsetBits, highOffsetBits] = getIntsFromOffset(offset); - nativeHandle->data[0] = dupfd; - nativeHandle->data[1] = prot; - nativeHandle->data[2] = lowOffsetBits; - nativeHandle->data[3] = highOffsetBits; - - // Create a NativeHandle which owns the native handle and fd so that we don't have to manually - // clean either the native handle or the fd. - auto ownedHandle = ::android::NativeHandle::create(nativeHandle, /*ownsHandle=*/true); + std::vector<int> ints = {prot, lowOffsetBits, highOffsetBits}; - return Memory{.handle = std::move(ownedHandle), .size = size, .name = "mmap_fd"}; + SharedHandle handle = std::make_shared<const Handle>(Handle{ + .fds = std::move(fds), + .ints = std::move(ints), + }); + return Memory{.handle = std::move(handle), .size = size, .name = "mmap_fd"}; } GeneralResult<Memory> createSharedMemoryFromHidlMemory(const hardware::hidl_memory& memory) { @@ -232,19 +271,20 @@ GeneralResult<Memory> createSharedMemoryFromAHWB(const AHardwareBuffer& ahwb) { AHardwareBuffer_describe(&ahwb, &bufferDesc); const native_handle_t* handle = AHardwareBuffer_getNativeHandle(&ahwb); - auto* cloned = native_handle_clone(handle); - auto nativeHandle = ::android::NativeHandle::create(cloned, /*ownsHandle=*/true); - if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) { return Memory{ - .handle = std::move(nativeHandle), + .handle = NN_TRY(sharedHandleFromNativeHandle(handle)), .size = bufferDesc.width, .name = "hardware_buffer_blob", }; } // memory size is not used for non-BLOB AHWB memory. - return Memory{.handle = std::move(nativeHandle), .size = 0, .name = "hardware_buffer"}; + return Memory{ + .handle = NN_TRY(sharedHandleFromNativeHandle(handle)), + .size = 0, + .name = "hardware_buffer", + }; } GeneralResult<Mapping> map(const Memory& memory) { diff --git a/nn/common/SharedMemoryHost.cpp b/nn/common/SharedMemoryHost.cpp index 231977cf7..eeb49075e 100644 --- a/nn/common/SharedMemoryHost.cpp +++ b/nn/common/SharedMemoryHost.cpp @@ -23,6 +23,7 @@ #include <limits> #include <memory> #include <utility> +#include <vector> #include "Result.h" #include "SharedMemory.h" @@ -36,7 +37,7 @@ GeneralResult<Mapping> mapAshmem(const Memory& memory) { CHECK_LE(memory.size, std::numeric_limits<uint32_t>::max()); const auto size = memory.size; - int fd = memory.handle->handle()->data[0]; + const int fd = memory.handle->fds[0]; std::shared_ptr<base::MappedFile> mapping = base::MappedFile::FromFd(fd, /*offset=*/0, size, PROT_READ | PROT_WRITE); if (mapping == nullptr) { @@ -54,10 +55,10 @@ struct MmapFdMappingContext { GeneralResult<Mapping> mapMemFd(const Memory& memory) { const size_t size = memory.size; - const native_handle_t* handle = memory.handle->handle(); - const int fd = handle->data[0]; - const int prot = handle->data[1]; - const size_t offset = getOffsetFromInts(handle->data[2], handle->data[3]); + const SharedHandle& handle = memory.handle; + const int fd = handle->fds[0]; + const int prot = handle->ints[0]; + const size_t offset = getOffsetFromInts(handle->ints[1], handle->ints[2]); std::shared_ptr<base::MappedFile> mapping = base::MappedFile::FromFd(fd, offset, size, prot); if (mapping == nullptr) { @@ -78,18 +79,14 @@ GeneralResult<Memory> createSharedMemory(size_t size) { << "ashmem_create_region(" << size << ") fails with " << fd; } - native_handle_t* handle = native_handle_create(1, 0); - if (handle == nullptr) { - // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here? - return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle"; - } - handle->data[0] = fd; - - // Create a NativeHandle which owns the native handle and fd so that we don't have to manually - // clean either the native handle or the fd. - auto nativeHandle = ::android::NativeHandle::create(handle, /*ownsHandle=*/true); + std::vector<base::unique_fd> fds; + fds.emplace_back(fd); - return Memory{.handle = std::move(nativeHandle), .size = size, .name = "ashmem"}; + SharedHandle handle = std::make_shared<const Handle>(Handle{ + .fds = std::move(fds), + .ints = {}, + }); + return Memory{.handle = std::move(handle), .size = size, .name = "ashmem"}; } GeneralResult<Memory> createSharedMemoryFromFd(size_t size, int prot, int fd, size_t offset) { @@ -98,31 +95,23 @@ GeneralResult<Memory> createSharedMemoryFromFd(size_t size, int prot, int fd, si } // Duplicate the file descriptor so the resultant Memory owns its own version. - int dupfd = dup(fd); - if (dupfd == -1) { + int dupFd = dup(fd); + if (dupFd == -1) { // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here? return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << "Failed to dup the fd"; } - // Create a temporary native handle to own the dupfd. - native_handle_t* nativeHandle = native_handle_create(1, 3); - if (nativeHandle == nullptr) { - close(dupfd); - // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here? - return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle"; - } + std::vector<base::unique_fd> fds; + fds.emplace_back(dupFd); const auto [lowOffsetBits, highOffsetBits] = getIntsFromOffset(offset); - nativeHandle->data[0] = dupfd; - nativeHandle->data[1] = prot; - nativeHandle->data[2] = lowOffsetBits; - nativeHandle->data[3] = highOffsetBits; - - // Create a NativeHandle which owns the native handle and fd so that we don't have to manually - // clean either the native handle or the fd. - auto ownedHandle = ::android::NativeHandle::create(nativeHandle, /*ownsHandle=*/true); + std::vector<int> ints = {prot, lowOffsetBits, highOffsetBits}; - return Memory{.handle = std::move(ownedHandle), .size = size, .name = "mmap_fd"}; + SharedHandle handle = std::make_shared<const Handle>(Handle{ + .fds = std::move(fds), + .ints = std::move(ints), + }); + return Memory{.handle = std::move(handle), .size = size, .name = "mmap_fd"}; } GeneralResult<Memory> createSharedMemoryFromHidlMemory(const hardware::hidl_memory& /*memory*/) { diff --git a/nn/common/TypeUtils.cpp b/nn/common/TypeUtils.cpp index 6d089bd2a..79d493e14 100644 --- a/nn/common/TypeUtils.cpp +++ b/nn/common/TypeUtils.cpp @@ -701,7 +701,7 @@ std::ostream& operator<<(std::ostream& os, const Operation& operation) { << ", .outputs=" << operation.outputs << "}"; } -std::ostream& operator<<(std::ostream& os, const NativeHandle& handle) { +std::ostream& operator<<(std::ostream& os, const SharedHandle& handle) { return os << (handle != nullptr ? "<non-empty handle>" : "<empty handle>"); } diff --git a/nn/common/Types.cpp b/nn/common/Types.cpp index 17485f442..e2e4cf112 100644 --- a/nn/common/Types.cpp +++ b/nn/common/Types.cpp @@ -17,7 +17,6 @@ #include "Types.h" #include <android-base/logging.h> -#include <cutils/native_handle.h> #include <errno.h> #include <poll.h> @@ -25,6 +24,7 @@ #include <cstddef> #include <iterator> #include <limits> +#include <memory> #include <optional> #include <utility> #include <vector> @@ -128,24 +128,32 @@ SyncFence SyncFence::createAsSignaled() { return SyncFence(nullptr); } -Result<SyncFence> SyncFence::create(NativeHandle syncFence) { - const bool isValid = (syncFence != nullptr && syncFence->handle() != nullptr && - syncFence->handle()->numFds == 1 && syncFence->handle()->numInts == 0 && - &syncFence->handle()->data[0] != nullptr); +SyncFence SyncFence::create(base::unique_fd fd) { + std::vector<base::unique_fd> fds; + fds.push_back(std::move(fd)); + return SyncFence(std::make_shared<const Handle>(Handle{ + .fds = std::move(fds), + .ints = {}, + })); +} + +Result<SyncFence> SyncFence::create(SharedHandle syncFence) { + const bool isValid = + (syncFence != nullptr && syncFence->fds.size() == 1 && syncFence->ints.empty()); if (!isValid) { return NN_ERROR() << "Invalid sync fence handle passed to SyncFence::create"; } return SyncFence(std::move(syncFence)); } -SyncFence::SyncFence(NativeHandle syncFence) : mSyncFence(std::move(syncFence)) {} +SyncFence::SyncFence(SharedHandle syncFence) : mSyncFence(std::move(syncFence)) {} SyncFence::FenceState SyncFence::syncWait(OptionalTimeout optionalTimeout) const { if (mSyncFence == nullptr) { return FenceState::SIGNALED; } - const int fd = mSyncFence->handle()->data[0]; + const int fd = mSyncFence->fds.front().get(); const int timeout = optionalTimeout.value_or(Timeout{-1}).count(); // This implementation is directly based on the ::sync_wait() implementation. @@ -182,8 +190,16 @@ SyncFence::FenceState SyncFence::syncWait(OptionalTimeout optionalTimeout) const return FenceState::UNKNOWN; } -NativeHandle SyncFence::getHandle() const { +SharedHandle SyncFence::getSharedHandle() const { return mSyncFence; } +bool SyncFence::hasFd() const { + return mSyncFence != nullptr; +} + +int SyncFence::getFd() const { + return mSyncFence == nullptr ? -1 : mSyncFence->fds.front().get(); +} + } // namespace android::nn diff --git a/nn/common/Validation.cpp b/nn/common/Validation.cpp index d37c447c0..1c939ba40 100644 --- a/nn/common/Validation.cpp +++ b/nn/common/Validation.cpp @@ -679,13 +679,15 @@ Result<Version> validateOperations(const std::vector<Operation>& operations, return version; } -Result<Version> validateNativeHandle(const NativeHandle& handle) { +Result<Version> validateSharedHandle(const SharedHandle& handle) { NN_VALIDATE(handle != nullptr); + NN_VALIDATE(std::all_of(handle->fds.begin(), handle->fds.end(), + [](const base::unique_fd& fd) { return fd.ok(); })); return Version::ANDROID_OC_MR1; } Result<Version> validateMemory(const Memory& memory) { - NN_TRY(validateNativeHandle(memory.handle)); + NN_TRY(validateSharedHandle(memory.handle)); if (memory.name == "ashmem") { NN_VALIDATE_NE(memory.size, 0u); @@ -2571,8 +2573,8 @@ Result<Version> validate(const Extension& extension) { return validateExtension(extension); } -Result<Version> validate(const NativeHandle& handle) { - return validateNativeHandle(handle); +Result<Version> validate(const SharedHandle& handle) { + return validateSharedHandle(handle); } Result<Version> validate(const Memory& memory) { @@ -2611,8 +2613,8 @@ Result<Version> validate(const std::vector<Extension>& extensions) { return validateExtensions(extensions); } -Result<Version> validate(const std::vector<NativeHandle>& handles) { - return validateVector(handles, validateNativeHandle); +Result<Version> validate(const std::vector<SharedHandle>& handles) { + return validateVector(handles, validateSharedHandle); } Result<Version> validate(const std::vector<BufferRole>& bufferRoles) { diff --git a/nn/common/include/nnapi/IDevice.h b/nn/common/include/nnapi/IDevice.h index 9a2e51680..75cf0a523 100644 --- a/nn/common/include/nnapi/IDevice.h +++ b/nn/common/include/nnapi/IDevice.h @@ -245,8 +245,8 @@ class IDevice { */ virtual GeneralResult<SharedPreparedModel> prepareModel( const Model& model, ExecutionPreference preference, Priority priority, - OptionalTimePoint deadline, const std::vector<NativeHandle>& modelCache, - const std::vector<NativeHandle>& dataCache, const CacheToken& token) const = 0; + OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache, + const std::vector<SharedHandle>& dataCache, const CacheToken& token) const = 0; /** * Creates a prepared model from cache files for execution. @@ -301,8 +301,8 @@ class IDevice { * for execution, otherwise GeneralError. */ virtual GeneralResult<SharedPreparedModel> prepareModelFromCache( - OptionalTimePoint deadline, const std::vector<NativeHandle>& modelCache, - const std::vector<NativeHandle>& dataCache, const CacheToken& token) const = 0; + OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache, + const std::vector<SharedHandle>& dataCache, const CacheToken& token) const = 0; /** * Allocates a driver-managed buffer with the properties specified by the descriptor as well as diff --git a/nn/common/include/nnapi/TypeUtils.h b/nn/common/include/nnapi/TypeUtils.h index 6b2af916f..b32f78b66 100644 --- a/nn/common/include/nnapi/TypeUtils.h +++ b/nn/common/include/nnapi/TypeUtils.h @@ -88,7 +88,7 @@ std::ostream& operator<<(std::ostream& os, std::ostream& operator<<(std::ostream& os, const Operand::ExtraParams& extraParams); std::ostream& operator<<(std::ostream& os, const Operand& operand); std::ostream& operator<<(std::ostream& os, const Operation& operation); -std::ostream& operator<<(std::ostream& os, const NativeHandle& handle); +std::ostream& operator<<(std::ostream& os, const SharedHandle& handle); std::ostream& operator<<(std::ostream& os, const Memory& memory); std::ostream& operator<<(std::ostream& os, const Model::Subgraph& subgraph); std::ostream& operator<<(std::ostream& os, const Model::OperandValues& operandValues); diff --git a/nn/common/include/nnapi/Types.h b/nn/common/include/nnapi/Types.h index 3b9725d27..5adab6bfa 100644 --- a/nn/common/include/nnapi/Types.h +++ b/nn/common/include/nnapi/Types.h @@ -18,8 +18,7 @@ #define ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_TYPES_H #include <android-base/expected.h> -#include <utils/NativeHandle.h> -#include <utils/StrongPointer.h> +#include <android-base/unique_fd.h> #include <array> #include <chrono> @@ -238,10 +237,15 @@ struct Operand { ExtraParams extraParams; }; -using NativeHandle = ::android::sp<::android::NativeHandle>; +struct Handle { + std::vector<base::unique_fd> fds; + std::vector<int> ints; +}; + +using SharedHandle = std::shared_ptr<const Handle>; struct Memory { - NativeHandle handle; + SharedHandle handle; size_t size = 0; std::string name; }; @@ -313,7 +317,8 @@ struct Request { class SyncFence { public: static SyncFence createAsSignaled(); - static Result<SyncFence> create(NativeHandle syncFence); + static SyncFence create(base::unique_fd fd); + static Result<SyncFence> create(SharedHandle syncFence); // The function syncWait() has the same semantics as the system function // ::sync_wait(), except that the syncWait() return value is semantically @@ -329,12 +334,14 @@ class SyncFence { FenceState syncWait(OptionalTimeout optionalTimeout) const; - NativeHandle getHandle() const; + SharedHandle getSharedHandle() const; + bool hasFd() const; + int getFd() const; private: - explicit SyncFence(NativeHandle syncFence); + explicit SyncFence(SharedHandle syncFence); - NativeHandle mSyncFence; + SharedHandle mSyncFence; }; using Clock = std::chrono::steady_clock; diff --git a/nn/common/include/nnapi/Validation.h b/nn/common/include/nnapi/Validation.h index 3eda174f6..ea213bdd8 100644 --- a/nn/common/include/nnapi/Validation.h +++ b/nn/common/include/nnapi/Validation.h @@ -42,7 +42,7 @@ Result<Version> validate(const OutputShape& outputShape); Result<Version> validate(const Timing& timing); Result<Version> validate(const Capabilities& capabilities); Result<Version> validate(const Extension& extension); -Result<Version> validate(const NativeHandle& handle); +Result<Version> validate(const SharedHandle& handle); Result<Version> validate(const Memory& memory); Result<Version> validate(const Model& model); Result<Version> validate(const BufferDesc& bufferDesc); @@ -53,7 +53,7 @@ Result<Version> validate(const OptionalTimeoutDuration& optionalTimeoutDuration) Result<Version> validate(const std::vector<OutputShape>& outputShapes); Result<Version> validate(const std::vector<Extension>& extensions); -Result<Version> validate(const std::vector<NativeHandle>& handles); +Result<Version> validate(const std::vector<SharedHandle>& handles); Result<Version> validate(const std::vector<BufferRole>& bufferRoles); // Validate request applied to model. diff --git a/nn/runtime/Manager.cpp b/nn/runtime/Manager.cpp index 90d58e490..d977878cd 100644 --- a/nn/runtime/Manager.cpp +++ b/nn/runtime/Manager.cpp @@ -432,8 +432,6 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM 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 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 @@ -443,12 +441,12 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM const auto [n1, inputPtrArgsMemory, inputPtrArgsLocations] = allocatePointerArgumentsToPool(inputs, &localMemories); if (n1 != ANEURALNETWORKS_NO_ERROR) { - return {n1, -1, nullptr, timing}; + return {n1, -1, nullptr, {}}; } const auto [n2, outputPtrArgsMemory, outputPtrArgsLocations] = allocatePointerArgumentsToPool(outputs, &localMemories); if (n2 != ANEURALNETWORKS_NO_ERROR) { - return {n2, -1, nullptr, timing}; + return {n2, -1, nullptr, {}}; } // Copy the input data that was specified via a pointer. @@ -475,28 +473,18 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM NNTRACE_FULL_SWITCH(NNTRACE_LAYER_IPC, NNTRACE_PHASE_EXECUTION, "DriverPreparedModel::executeFenced"); - int n = ANEURALNETWORKS_OP_FAILED; - 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); - if (nativeHandle == nullptr) { - LOG(ERROR) << "Failed to create native_handle"; - return {n, -1, nullptr, timing}; - } - int dupFd = dup(waitFor[i]); + std::vector<SyncFence> waitForHandles; + waitForHandles.reserve(waitFor.size()); + for (int fd : waitFor) { + int dupFd = dup(fd); if (dupFd <= 0) { LOG(ERROR) << "Unable to dup the file descriptor"; - return {n, -1, nullptr, timing}; + return {ANEURALNETWORKS_OP_FAILED, -1, nullptr, {}}; } - nativeHandle->data[0] = dupFd; - hardware::hidl_handle hidlHandle; - hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true); - waitForHandles[i] = std::move(hidlHandle); + waitForHandles.push_back(SyncFence::create(base::unique_fd(dupFd))); } - hardware::hidl_handle syncFence; - std::tie(n, syncFence, executeFencedCallback, timing) = + auto [n, syncFence, executeFencedCallback, timing] = mPreparedModel->executeFenced(request, waitForHandles, measure, deadline, loopTimeoutDuration, timeoutDurationAfterFence); @@ -506,8 +494,8 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM } int syncFenceFd = -1; - if (syncFence.getNativeHandle()) { - syncFenceFd = dup(syncFence.getNativeHandle()->data[0]); + if (syncFence.hasFd()) { + syncFenceFd = dup(syncFence.getFd()); if (syncFenceFd < 0) { LOG(ERROR) << "Failed to dup the file descriptor"; return {ANEURALNETWORKS_OP_FAILED, -1, nullptr, timing}; diff --git a/nn/runtime/VersionedInterfaces.cpp b/nn/runtime/VersionedInterfaces.cpp index fce558c38..8246b623e 100644 --- a/nn/runtime/VersionedInterfaces.cpp +++ b/nn/runtime/VersionedInterfaces.cpp @@ -24,6 +24,7 @@ #include <android-base/thread_annotations.h> #include <cutils/native_handle.h> #include <fcntl.h> +#include <nnapi/hal/CommonUtils.h> #include <algorithm> #include <chrono> @@ -416,67 +417,83 @@ static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction( return result; } -std::tuple<int, hardware::hidl_handle, sp<V1_3::IFencedExecutionCallback>, Timing> +std::tuple<int, SyncFence, sp<V1_3::IFencedExecutionCallback>, Timing> VersionedIPreparedModel::executeFenced(const Request& request, - const hardware::hidl_vec<hardware::hidl_handle>& waitFor, - MeasureTiming measure, + const std::vector<SyncFence>& waitFor, MeasureTiming measure, const std::optional<Deadline>& deadline, const OptionalTimeoutDuration& loopTimeoutDuration, const OptionalTimeoutDuration& timeoutDurationAfterFence) { // version 1.3 HAL - hardware::hidl_handle syncFence; + hardware::hidl_handle hidlSyncFence; sp<V1_3::IFencedExecutionCallback> dispatchCallback; Timing timing = {UINT64_MAX, UINT64_MAX}; if (mPreparedModelV1_3 != nullptr) { ErrorStatus errorStatus; const auto otp = makeTimePoint(deadline); + auto waitForHandles = hal::utils::convertSyncFences(waitFor); + if (!waitForHandles.has_value()) { + LOG(ERROR) << "executeFenced failure: " << waitForHandles.error().message; + return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(), + nullptr, timing); + } 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]( + convertToV1_3(request), std::move(waitForHandles).value(), convertToV1_2(measure), + convertToV1_3(otp), convertToV1_3(loopTimeoutDuration), + convertToV1_3(timeoutDurationAfterFence), + [&hidlSyncFence, &errorStatus, &dispatchCallback]( V1_3::ErrorStatus error, const hardware::hidl_handle& handle, const sp<V1_3::IFencedExecutionCallback>& callback) { - syncFence = handle; + hidlSyncFence = handle; errorStatus = uncheckedConvert(error); dispatchCallback = callback; }); if (!ret.isOk()) { LOG(ERROR) << "executeFenced failure: " << ret.description(); - return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hardware::hidl_handle(nullptr), + return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(), nullptr, timing); } if (errorStatus != ErrorStatus::NONE) { LOG(ERROR) << "executeFenced returned " << errorStatus; return std::make_tuple(convertErrorStatusToResultCode(errorStatus), - hardware::hidl_handle(nullptr), nullptr, timing); + SyncFence::createAsSignaled(), nullptr, timing); } - return std::make_tuple(ANEURALNETWORKS_NO_ERROR, syncFence, dispatchCallback, timing); + auto sharedHandle = hal::utils::sharedHandleFromNativeHandle(hidlSyncFence); + if (!sharedHandle.has_value()) { + LOG(ERROR) << "executeFenced failure: " << sharedHandle.error().message; + return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(), + nullptr, timing); + } + auto syncFence = sharedHandle.value() == nullptr + ? SyncFence::createAsSignaled() + : SyncFence::create(std::move(sharedHandle).value()); + if (!syncFence.has_value()) { + LOG(ERROR) << "executeFenced failure: " << syncFence.error(); + return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(), + nullptr, timing); + } + return std::make_tuple(ANEURALNETWORKS_NO_ERROR, std::move(syncFence).value(), + dispatchCallback, timing); } // fallback to synchronous execution if sync_fence is not supported // first wait for all sync fences to be ready. 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, hardware::hidl_handle(nullptr), - nullptr, timing); - } - int syncFd = fenceHandle.getNativeHandle()->data[0]; - if (syncFd <= 0) { - return std::make_tuple(ANEURALNETWORKS_BAD_DATA, hardware::hidl_handle(nullptr), - nullptr, timing); + for (const auto& fence : waitFor) { + if (!fence.hasFd() || fence.getFd() <= 0) { + return std::make_tuple(ANEURALNETWORKS_BAD_DATA, SyncFence::createAsSignaled(), nullptr, + timing); } - auto r = syncWait(syncFd, -1); - if (r != FenceState::SIGNALED) { - LOG(ERROR) << "syncWait failed, fd: " << syncFd; - return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hardware::hidl_handle(nullptr), + auto r = fence.syncWait({/* no timeout */}); + if (r != SyncFence::FenceState::SIGNALED) { + LOG(ERROR) << "syncWait failed, fd: " << fence.getFd() << ", state: " << r; + return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(), nullptr, timing); } } int errorCode; std::tie(errorCode, std::ignore, timing) = executeSynchronously(request, measure, deadline, loopTimeoutDuration); - return std::make_tuple(errorCode, hardware::hidl_handle(nullptr), nullptr, timing); + return std::make_tuple(errorCode, SyncFence::createAsSignaled(), nullptr, timing); } static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction( diff --git a/nn/runtime/VersionedInterfaces.h b/nn/runtime/VersionedInterfaces.h index d41dcd3ad..bd7e396bf 100644 --- a/nn/runtime/VersionedInterfaces.h +++ b/nn/runtime/VersionedInterfaces.h @@ -754,8 +754,8 @@ class VersionedIPreparedModel { * all sync fences in waitFor are signaled. * @return A tuple consisting of: * - Error code of the dispatch call. - * - A sync_fence that will be triggered when the task is completed. - * The sync_fence will be set to error if critical error occurs when doing + * - A SyncFence that will be triggered when the task is completed. + * The SyncFence will be set to error if critical error occurs when doing * actual evaluation. * - A callback can be used to query information like duration * and detailed runtime error status when the task is completed. @@ -763,11 +763,11 @@ class VersionedIPreparedModel { * sync execution. Either IFencedExecutionCallback will be * returned or optional timing information is returned */ - 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); + std::tuple<int, SyncFence, sp<V1_3::IFencedExecutionCallback>, Timing> executeFenced( + const Request& request, const std::vector<SyncFence>& waitFor, MeasureTiming measure, + const std::optional<Deadline>& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + const OptionalTimeoutDuration& timeoutDurationAfterFence); private: friend class VersionedIDevice; diff --git a/nn/runtime/test/TestVersionedInterfaces.cpp b/nn/runtime/test/TestVersionedInterfaces.cpp index b4f32bcde..4187029f9 100644 --- a/nn/runtime/test/TestVersionedInterfaces.cpp +++ b/nn/runtime/test/TestVersionedInterfaces.cpp @@ -2182,7 +2182,7 @@ TEST_F(VersionedIPreparedModelV1_0Test, executeFenced) { // verify success EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2198,7 +2198,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFenced) { // verify success EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2214,7 +2214,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFenced) { // verify success EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2235,7 +2235,7 @@ TEST_F(VersionedIPreparedModelV1_3Test, executeFenced) { // verify success EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); - EXPECT_NE(nullptr, syncFence.getNativeHandle()); + EXPECT_NE(nullptr, syncFence.getSharedHandle()); EXPECT_NE(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2494,7 +2494,7 @@ TEST_F(VersionedIPreparedModelV1_0Test, executeFencedFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2511,7 +2511,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFencedFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2528,7 +2528,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFencedFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2550,7 +2550,7 @@ TEST_F(VersionedIPreparedModelV1_3Test, executeFencedFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2759,7 +2759,7 @@ TEST_F(VersionedIPreparedModelV1_0Test, executeFencedTransportFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2776,7 +2776,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFencedTransportFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2793,7 +2793,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFencedTransportFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } @@ -2810,7 +2810,7 @@ TEST_F(VersionedIPreparedModelV1_3Test, executeFencedTransportFailure) { // verify failure EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); - EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, syncFence.getSharedHandle()); EXPECT_EQ(nullptr, dispatchCallback.get()); EXPECT_EQ(kNoTiming, timing); } |