1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "Manager"
18
19 #include "Manager.h"
20 #include "HalInterfaces.h"
21 #include "Utils.h"
22
23 #include <android/hidl/manager/1.0/IServiceManager.h>
24 #include <hidl/HidlTransportSupport.h>
25 #include <hidl/ServiceManagement.h>
26
27 #include <algorithm>
28 #include <functional>
29
30 namespace android {
31 namespace nn {
32
33 // TODO: handle errors from initialize correctly
initialize()34 bool Device::initialize() {
35 #ifdef NN_DEBUGGABLE
36 static const char samplePrefix[] = "sample";
37
38 mSupported =
39 (mName.substr(0, sizeof(samplePrefix) - 1) == samplePrefix)
40 ? getProp("debug.nn.sample.supported") : 0;
41 #endif // NN_DEBUGGABLE
42 bool success = false;
43 auto ret = mInterface->getCapabilities([&](ErrorStatus status,
44 const Capabilities& capabilities) {
45 if (status != ErrorStatus::NONE) {
46 LOG(ERROR) << "IDevice::getCapabilities returned the error " << toString(status);
47 } else {
48 VLOG(MANAGER) << "Capab " << capabilities.float32Performance.execTime;
49 VLOG(MANAGER) << "Capab " << capabilities.quantized8Performance.execTime;
50 mFloat32Performance = capabilities.float32Performance;
51 mQuantized8Performance = capabilities.quantized8Performance;
52 success = true;
53 }
54 });
55 if (!ret.isOk()) {
56 LOG(ERROR) << "IDevice::getCapabilities failed for " << getName()
57 << ": " << ret.description();
58 }
59 return success;
60 }
61
getSupportedOperations(const Model & hidlModel,hidl_vec<bool> * outSupportedOperations) const62 void Device::getSupportedOperations(const Model& hidlModel,
63 hidl_vec<bool>* outSupportedOperations) const {
64 auto ret = mInterface->getSupportedOperations(
65 hidlModel,
66 [outSupportedOperations](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
67 if (status != ErrorStatus::NONE) {
68 LOG(ERROR)
69 << "IDevice::getSupportedOperations returned the error "
70 << toString(status);
71 }
72 *outSupportedOperations = supportedOperations;
73 });
74
75 if (!ret.isOk()) {
76 LOG(ERROR) << "IDevice::getSupportedOperations failed for " << getName()
77 << ": " << ret.description();
78 outSupportedOperations->resize(hidlModel.operations.size());
79 std::fill(outSupportedOperations->begin(), outSupportedOperations->end(), false);
80 return;
81 }
82
83 #ifdef NN_DEBUGGABLE
84 if (mSupported != 1) {
85 return;
86 }
87
88 const uint32_t baseAccumulator = std::hash<std::string>{}(mName);
89 for (size_t operationIndex = 0; operationIndex < outSupportedOperations->size();
90 operationIndex++) {
91 if (!(*outSupportedOperations)[operationIndex]) {
92 continue;
93 }
94
95 uint32_t accumulator = baseAccumulator;
96 const Operation &operation = hidlModel.operations[operationIndex];
97 accumulator ^= static_cast<uint32_t>(operation.type);
98 auto accumulateOperands = [&hidlModel, &accumulator](const hidl_vec<uint32_t>& operands) {
99 for (uint32_t operandIndex : operands) {
100 const Operand& operand = hidlModel.operands[operandIndex];
101 accumulator ^= static_cast<uint32_t>(operand.type);
102 accumulator ^= operand.dimensions.size();
103 for (uint32_t dimension : operand.dimensions) {
104 accumulator ^= dimension;
105 if (operand.lifetime == OperandLifeTime::CONSTANT_COPY ||
106 operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE) {
107 accumulator ^= 1;
108 }
109 }
110 }
111 };
112 accumulateOperands(operation.inputs);
113 accumulateOperands(operation.outputs);
114 if (accumulator & 1) {
115 (*outSupportedOperations)[operationIndex] = false;
116 }
117 }
118 #endif // NN_DEBUGGABLE
119 }
120
get()121 DeviceManager* DeviceManager::get() {
122 static DeviceManager manager;
123 return &manager;
124 }
125
findAvailableDevices()126 void DeviceManager::findAvailableDevices() {
127 using ::android::hardware::neuralnetworks::V1_0::IDevice;
128 using ::android::hidl::manager::V1_0::IServiceManager;
129 VLOG(MANAGER) << "findAvailableDevices";
130
131 sp<IServiceManager> manager = hardware::defaultServiceManager();
132 if (manager == nullptr) {
133 LOG(ERROR) << "Unable to open defaultServiceManager";
134 return;
135 }
136
137 manager->listByInterface(IDevice::descriptor, [this](const hidl_vec<hidl_string>& names) {
138 for (const auto& name : names) {
139 VLOG(MANAGER) << "Found interface " << name.c_str();
140 sp<IDevice> device = IDevice::getService(name);
141 if (device == nullptr) {
142 LOG(ERROR) << "Got a null IDEVICE for " << name.c_str();
143 continue;
144 }
145 registerDevice(name.c_str(), device);
146 }
147 });
148 }
149
registerDevice(const char * name,const sp<IDevice> & device)150 void DeviceManager::registerDevice(const char* name, const sp<IDevice>& device) {
151 auto d = std::make_shared<Device>(name, device);
152 if (d->initialize()) {
153 mDevices.push_back(d);
154 }
155 }
156
DeviceManager()157 DeviceManager::DeviceManager() {
158 VLOG(MANAGER) << "DeviceManager::DeviceManager";
159 findAvailableDevices();
160 #ifdef NN_DEBUGGABLE
161 mPartitioning = getProp("debug.nn.partition", kPartitioningDefault);
162 #endif // NN_DEBUGGABLE
163 }
164
165 } // namespace nn
166 } // namespace android
167