Implement fallback strategy of device memory allocation.
Currently, NNAPI will always fallback to ashmem if the driver fails to
allocate device memory, or if memory domain is not supported on the
related devices. This CL changes this behavior to only fallback if the
related compilations are not created with introspection API.
Bug: 147886012
Test: NNT_static
Change-Id: I93486c6bcb2edd12e0095d79f49bdde679c82d73
Merged-In: I93486c6bcb2edd12e0095d79f49bdde679c82d73
Merged-In: I93486c6bcb2edd12e0095d79f49bdde679c82d73
(cherry picked from commit 02249d9e0e515cd0b71abaa93df1243f09a21936)
(cherry picked from commit 26a3beaade8ef2f45e55bc795069178e9d1a1853)
diff --git a/runtime/CompilationBuilder.h b/runtime/CompilationBuilder.h
index 66ef5b9..d94fb18 100644
--- a/runtime/CompilationBuilder.h
+++ b/runtime/CompilationBuilder.h
@@ -68,6 +68,8 @@
const ExecutionPlan& forTest_getExecutionPlan() const { return mPlan; }
+ bool createdWithExplicitDeviceList() const { return mExplicitDeviceList; }
+
private:
const ModelBuilder* mModel;
diff --git a/runtime/Manager.cpp b/runtime/Manager.cpp
index 42f9262..db3cd6b 100644
--- a/runtime/Manager.cpp
+++ b/runtime/Manager.cpp
@@ -40,6 +40,7 @@
#include "MetaModel.h"
#include "ModelArgumentInfo.h"
#include "Tracing.h"
+#include "TypeManager.h"
#include "Utils.h"
#include "VersionedInterfaces.h"
@@ -101,7 +102,8 @@
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) const override;
+ std::pair<int, std::unique_ptr<Memory>> allocate(const MemoryDescriptor& desc,
+ hal::OperandType) const override;
private:
const std::shared_ptr<VersionedIDevice> kInterface;
@@ -248,7 +250,8 @@
return {ANEURALNETWORKS_NO_ERROR, std::make_shared<DriverPreparedModel>(this, preparedModel)};
}
-std::pair<int, std::unique_ptr<Memory>> DriverDevice::allocate(const MemoryDescriptor& desc) const {
+std::pair<int, std::unique_ptr<Memory>> DriverDevice::allocate(const MemoryDescriptor& desc,
+ hal::OperandType) const {
const BufferDesc hidlDesc = {.dimensions = desc.dimensions};
std::vector<std::shared_ptr<VersionedIPreparedModel>> preparedModels(
desc.preparedModels.size());
@@ -572,11 +575,8 @@
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&) const override {
- // CpuDevice does not have a preferred memory domain or data layout, return failure to
- // fallback to ashmem.
- return {ANEURALNETWORKS_OP_FAILED, nullptr};
- }
+ std::pair<int, std::unique_ptr<Memory>> allocate(const MemoryDescriptor& desc,
+ OperandType type) const override;
private:
CpuDevice() = default;
@@ -663,6 +663,16 @@
return CpuPreparedModel::create(model);
}
+std::pair<int, std::unique_ptr<Memory>> 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.";
+ return {ANEURALNETWORKS_OP_FAILED, nullptr};
+ }
+ return MemoryAshmem::create(size);
+}
+
std::pair<int, std::shared_ptr<PreparedModel>> CpuPreparedModel::create(Model hidlModel) {
std::vector<RunTimePoolInfo> poolInfos;
if (!setRunTimePoolInfosFromHidlMemories(&poolInfos, hidlModel.pools)) {
diff --git a/runtime/Manager.h b/runtime/Manager.h
index f634c2d..0ece99b 100644
--- a/runtime/Manager.h
+++ b/runtime/Manager.h
@@ -110,8 +110,8 @@
// 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) const = 0;
+ virtual std::pair<int, std::unique_ptr<Memory>> allocate(const MemoryDescriptor& desc,
+ hal::OperandType type) const = 0;
};
// Manages the NN HAL devices. Only one instance of this class will exist.
diff --git a/runtime/Memory.cpp b/runtime/Memory.cpp
index 5c8136f..9bddcd9 100644
--- a/runtime/Memory.cpp
+++ b/runtime/Memory.cpp
@@ -456,6 +456,10 @@
logMemoryDescriptorToInfo(mDesc, mOperand.value());
}
mAllocator = selectDeviceMemoryAllocator(mDesc);
+ mShouldFallback = std::none_of(mRoles.begin(), mRoles.end(), [](const auto& role) {
+ const auto* cb = std::get<const CompilationBuilder*>(role);
+ return cb->createdWithExplicitDeviceList();
+ });
mFinished = true;
return ANEURALNETWORKS_NO_ERROR;
}
@@ -480,13 +484,12 @@
// Try allocate the memory on device.
if (mAllocator != nullptr) {
- std::tie(n, memory) = mAllocator->allocate(mDesc);
+ std::tie(n, memory) = mAllocator->allocate(mDesc, mOperand->type);
}
// If failed, fallback to ashmem.
- // TODO(xusongw): Decide on the fallback strategy.
// TODO(xusongw): Use BLOB mode hardware buffer when possible.
- if (n != ANEURALNETWORKS_NO_ERROR) {
+ if (n != ANEURALNETWORKS_NO_ERROR && mShouldFallback) {
VLOG(MEMORY) << "MemoryBuilder::allocate -- fallback to ashmem.";
std::tie(n, memory) = MemoryAshmem::create(size);
}
diff --git a/runtime/Memory.h b/runtime/Memory.h
index 8d03417..80c5251 100644
--- a/runtime/Memory.h
+++ b/runtime/Memory.h
@@ -247,7 +247,14 @@
// Once the descriptor has been finished, we should not allow further modifications.
bool mFinished = false;
+ // The following fields are only valid when finished.
+
+ // The chosen device to allocate the memory. Set to nullptr if there are multiple devices.
const Device* mAllocator = nullptr;
+
+ // If set to true, allocate() will fallback to Ashmem or AHardwareBuffer if the memory
+ // allocation fails on the chosen device, or if there is no device chosen.
+ bool mShouldFallback = true;
};
class MemoryAshmem : public Memory {