summaryrefslogtreecommitdiff
path: root/nn/runtime/Manager.cpp
diff options
context:
space:
mode:
authorXusong Wang <xusongw@google.com>2018-10-25 18:49:54 -0700
committerXusong Wang <xusongw@google.com>2018-12-14 10:57:59 -0800
commit8e0bbbd6b982156823be0ce336f8af2090b47bed (patch)
tree2f182f71a24ae2b28dc09531fc9fb5d1ed6a74db /nn/runtime/Manager.cpp
parent6984a7b7007e427015f6ee3303d7acb039788a1c (diff)
downloadml-8e0bbbd6b982156823be0ce336f8af2090b47bed.tar.gz
Wrap the CpuExecutor as a device during compilation step.
Make Device a common interface for abstraction of CPU fallback as well as the actual driver devices. Modify the compilation steps, mainly the partitioner, to accommodate the change. Make all possible compilation outcomes plan-based, even for the CPU fallback, which is a SIMPLE body running on CPU only. Add validation for invalid empty model and create validation test. Add validation for empty device list passed to introspection and control API and create tests. Bug: 72506261 Test: NeuralNetworksTest_static Change-Id: Ic63036716afb8a0156c77e0cf43456e490783deb
Diffstat (limited to 'nn/runtime/Manager.cpp')
-rw-r--r--nn/runtime/Manager.cpp175
1 files changed, 165 insertions, 10 deletions
diff --git a/nn/runtime/Manager.cpp b/nn/runtime/Manager.cpp
index b79002d68..63d20c3af 100644
--- a/nn/runtime/Manager.cpp
+++ b/nn/runtime/Manager.cpp
@@ -17,30 +17,76 @@
#define LOG_TAG "Manager"
#include "Manager.h"
+#include "Callbacks.h"
#include "HalInterfaces.h"
+#include "Tracing.h"
#include "Utils.h"
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <build/version.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/ServiceManagement.h>
#include <algorithm>
#include <functional>
+using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+
namespace android {
namespace nn {
-Device::Device(std::string name, const sp<V1_0::IDevice>& device) :
- mName(std::move(name)), mInterface(device) {}
+// A Device with actual underlying driver
+class DriverDevice : public Device {
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DriverDevice);
+
+ public:
+ DriverDevice(std::string name, const sp<V1_0::IDevice>& device);
+
+ // Returns true if succesfully initialized.
+ bool initialize();
+
+ const char* getName() const override { return mName.c_str(); }
+ const char* getVersionString() const override { return mVersionString.c_str(); }
+ VersionedIDevice* getInterface() override { return &mInterface; }
+ int64_t getFeatureLevel() override { return mInterface.getFeatureLevel(); }
+ void getSupportedOperations(const Model& hidlModel, hidl_vec<bool>* supported) override;
+ PerformanceInfo getFloat32Performance() const override { return mFloat32Performance; }
+ PerformanceInfo getQuantized8Performance() const override { return mQuantized8Performance; }
+ PerformanceInfo getRelaxedFloat32toFloat16Performance() const override {
+ return mRelaxedFloat32toFloat16Performance;
+ }
+
+ int prepareModel(const Model& hidlModel, ExecutionPreference executionPreference,
+ std::shared_ptr<VersionedIPreparedModel>* preparedModel) override;
+
+ private:
+ std::string mName;
+ std::string mVersionString;
+ VersionedIDevice mInterface;
+ PerformanceInfo mFloat32Performance;
+ PerformanceInfo mQuantized8Performance;
+ PerformanceInfo mRelaxedFloat32toFloat16Performance;
+
+#ifdef NN_DEBUGGABLE
+ // For debugging: behavior of IDevice::getSupportedOperations for SampleDriver.
+ // 0 - all operations reported by IDevice::getSupportedOperations() supported
+ // 1 - some operations reported by IDevice::getSupportedOperations() supported
+ uint32_t mSupported = 0;
+#endif // NN_DEBUGGABLE
+};
+
+DriverDevice::DriverDevice(std::string name, const sp<V1_0::IDevice>& device)
+ : mName(std::move(name)), mInterface(device) {}
// TODO: handle errors from initialize correctly
-bool Device::initialize() {
+bool DriverDevice::initialize() {
#ifdef NN_DEBUGGABLE
static const char samplePrefix[] = "sample";
- mSupported =
- (mName.substr(0, sizeof(samplePrefix) - 1) == samplePrefix)
- ? getProp("debug.nn.sample.supported") : 0;
+ mSupported = (mName.substr(0, sizeof(samplePrefix) - 1) == samplePrefix)
+ ? getProp("debug.nn.sample.supported")
+ : 0;
#endif // NN_DEBUGGABLE
ErrorStatus status = ErrorStatus::GENERAL_FAILURE;
@@ -68,8 +114,8 @@ bool Device::initialize() {
return status == ErrorStatus::NONE;
}
-void Device::getSupportedOperations(const Model& hidlModel,
- hidl_vec<bool>* outSupportedOperations) {
+void DriverDevice::getSupportedOperations(const Model& hidlModel,
+ hidl_vec<bool>* outSupportedOperations) {
// Query the driver for what it can do.
ErrorStatus status = ErrorStatus::GENERAL_FAILURE;
hidl_vec<bool> supportedOperations;
@@ -92,7 +138,7 @@ void Device::getSupportedOperations(const Model& hidlModel,
return;
}
- *outSupportedOperations = supportedOperations;
+ *outSupportedOperations = std::move(supportedOperations);
#ifdef NN_DEBUGGABLE
if (mSupported != 1) {
@@ -132,11 +178,116 @@ void Device::getSupportedOperations(const Model& hidlModel,
#endif // NN_DEBUGGABLE
}
+// Compilation logic copied from StepExecutor::startComputeOnDevice().
+int DriverDevice::prepareModel(const Model& hidlModel, ExecutionPreference executionPreference,
+ std::shared_ptr<VersionedIPreparedModel>* preparedModel) {
+ *preparedModel = nullptr;
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+
+ // Note that some work within VersionedIDevice will be subtracted from the
+ // IPC layer
+ NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "prepareModel");
+ Return<ErrorStatus> prepareLaunchStatus =
+ mInterface.prepareModel(hidlModel, executionPreference, preparedModelCallback);
+ if (!prepareLaunchStatus.isOk()) {
+ LOG(ERROR) << "ExecutionStep::finishSubModel compilation failed due to transport error: "
+ << prepareLaunchStatus.description();
+ return ANEURALNETWORKS_OP_FAILED;
+ }
+ if (prepareLaunchStatus != ErrorStatus::NONE) {
+ LOG(ERROR) << "ExecutionStep::finishSubModel compilation failed with error: "
+ << toString(static_cast<ErrorStatus>(prepareLaunchStatus));
+ return ANEURALNETWORKS_OP_FAILED;
+ }
+
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ if (auto returnedPreparedModel = preparedModelCallback->getPreparedModel()) {
+ *preparedModel = std::make_shared<VersionedIPreparedModel>(returnedPreparedModel);
+ }
+ if (prepareReturnStatus != ErrorStatus::NONE || *preparedModel == nullptr) {
+ LOG(ERROR) << "ExecutionPlan compilation on " << getName() << " failed:"
+ << " prepareReturnStatus=" << toString(prepareReturnStatus)
+ << ", preparedModel=" << preparedModel->get();
+ return ANEURALNETWORKS_OP_FAILED;
+ }
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+// A special abstracted device for the CPU. Only one instance of this class will exist.
+// Use get() to retrieve it.
+class CpuDevice : public Device {
+ DISALLOW_COPY_AND_ASSIGN(CpuDevice);
+
+ public:
+ // Returns the singleton CPU fallback device.
+ static std::shared_ptr<CpuDevice> get() {
+ static std::shared_ptr<CpuDevice> instance(new CpuDevice);
+ return instance;
+ }
+
+ const char* getName() const override { return kName.c_str(); }
+ const char* getVersionString() const override { return kVersionString.c_str(); }
+ VersionedIDevice* getInterface() override { return nullptr; }
+ int64_t getFeatureLevel() override { return kFeatureLevel; }
+ void getSupportedOperations(const Model& hidlModel, hidl_vec<bool>* supported) override;
+ PerformanceInfo getFloat32Performance() const override { return kPerformance; }
+ PerformanceInfo getQuantized8Performance() const override { return kPerformance; }
+ PerformanceInfo getRelaxedFloat32toFloat16Performance() const override { return kPerformance; }
+
+ int prepareModel(const Model& hidlModel, ExecutionPreference executionPreference,
+ std::shared_ptr<VersionedIPreparedModel>* preparedModel) override;
+
+ private:
+ CpuDevice() = default;
+ const int64_t kFeatureLevel = __ANDROID_API__;
+ const std::string kName = "google-cpu";
+ 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};
+};
+
+void CpuDevice::getSupportedOperations(const Model& hidlModel, hidl_vec<bool>* supported) {
+ const size_t count = hidlModel.operations.size();
+ hidl_vec<bool> supportedOperations(count);
+ for (size_t i = 0; i < count; i++) {
+ // TODO(b/119870033): Decide whether and how post-P operations would be supported on CPU.
+ // CPU fallback should support all the operations except for OEM_OPERATION
+ if (hidlModel.operations[i].type == OperationType::OEM_OPERATION) {
+ supportedOperations[i] = false;
+ } else {
+ supportedOperations[i] = true;
+ }
+ }
+ *supported = std::move(supportedOperations);
+}
+
+int CpuDevice::prepareModel(const Model& hidlModel, ExecutionPreference executionPreference,
+ std::shared_ptr<VersionedIPreparedModel>* preparedModel) {
+ *preparedModel = nullptr;
+ if (!validateModel(hidlModel) || !validateExecutionPreference(executionPreference)) {
+ return ANEURALNETWORKS_OP_FAILED;
+ }
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
DeviceManager* DeviceManager::get() {
static DeviceManager manager;
return &manager;
}
+std::shared_ptr<Device> DeviceManager::getCpuDevice() {
+ return CpuDevice::get();
+}
+
+std::shared_ptr<Device> DeviceManager::forTest_makeDriverDevice(const std::string& name,
+ const sp<V1_0::IDevice>& device) {
+ auto driverDevice = std::make_shared<DriverDevice>(name, device);
+ CHECK(driverDevice->initialize());
+ return driverDevice;
+}
+
void DeviceManager::findAvailableDevices() {
using ::android::hidl::manager::V1_0::IServiceManager;
VLOG(MANAGER) << "findAvailableDevices";
@@ -158,10 +309,14 @@ void DeviceManager::findAvailableDevices() {
registerDevice(name.c_str(), device);
}
});
+
+ // register CPU fallback device
+ mDevices.push_back(CpuDevice::get());
+ mDevicesCpuOnly.push_back(CpuDevice::get());
}
void DeviceManager::registerDevice(const char* name, const sp<V1_0::IDevice>& device) {
- auto d = std::make_shared<Device>(name, device);
+ auto d = std::make_shared<DriverDevice>(name, device);
if (d->initialize()) {
mDevices.push_back(d);
}