blob: 0298f3b71d1617b691d1e0ff929c29b715c2c350 [file] [log] [blame]
telsoa01ce3e84a2018-08-31 09:31:35 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// See LICENSE file in the project root for full license information.
4//
5
Matteo Martincighe48bdff2018-09-03 13:50:50 +01006#define LOG_TAG "ArmnnDriver"
7
telsoa01ce3e84a2018-08-31 09:31:35 +01008#include "ArmnnDriverImpl.hpp"
9#include "ModelToINetworkConverter.hpp"
10#include "ArmnnPreparedModel.hpp"
11#include "SystemPropertiesUtils.hpp"
12
13#if defined(ARMNN_ANDROID_P)
14// The headers of the ML framework have changed between Android O and Android P.
15// The validation functions have been moved into their own header, ValidateHal.h.
16#include <ValidateHal.h>
17#endif
18
19#include <log/log.h>
20
21using namespace std;
22using namespace android;
23using namespace android::nn;
24using namespace android::hardware;
25
26namespace
27{
28
29const char *g_Float32PerformanceExecTimeName = "ArmNN.float32Performance.execTime";
30const char *g_Float32PerformancePowerUsageName = "ArmNN.float32Performance.powerUsage";
31const char *g_Quantized8PerformanceExecTimeName = "ArmNN.quantized8Performance.execTime";
32const char *g_Quantized8PerformancePowerUsageName = "ArmNN.quantized8Performance.powerUsage";
33
34void NotifyCallbackAndCheck(const sp<IPreparedModelCallback>& callback,
35 ErrorStatus errorStatus,
36 const sp<IPreparedModel>& preparedModelPtr)
37{
38 Return<void> returned = callback->notify(errorStatus, preparedModelPtr);
39 // This check is required, if the callback fails and it isn't checked it will bring down the service
40 if (!returned.isOk())
41 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +010042 ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
telsoa01ce3e84a2018-08-31 09:31:35 +010043 returned.description().c_str());
44 }
45}
46
47Return<ErrorStatus> FailPrepareModel(ErrorStatus error,
48 const string& message,
49 const sp<IPreparedModelCallback>& callback)
50{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010051 ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str());
telsoa01ce3e84a2018-08-31 09:31:35 +010052 NotifyCallbackAndCheck(callback, error, nullptr);
53 return error;
54}
55
56} // namespace
57
58namespace armnn_driver
59{
telsoa01ce3e84a2018-08-31 09:31:35 +010060
Matteo Martincighe48bdff2018-09-03 13:50:50 +010061template <typename HalVersion>
62Return<void> ArmnnDriverImpl<HalVersion>::getCapabilities(
telsoa01ce3e84a2018-08-31 09:31:35 +010063 const armnn::IRuntimePtr& runtime,
Matteo Martincighe48bdff2018-09-03 13:50:50 +010064 HalGetCapabilities_cb cb)
telsoa01ce3e84a2018-08-31 09:31:35 +010065{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010066 ALOGV("ArmnnDriverImpl::getCapabilities()");
telsoa01ce3e84a2018-08-31 09:31:35 +010067
Matteo Martincighe48bdff2018-09-03 13:50:50 +010068 HalCapabilities capabilities;
telsoa01ce3e84a2018-08-31 09:31:35 +010069 if (runtime)
70 {
71 capabilities.float32Performance.execTime =
72 ParseSystemProperty(g_Float32PerformanceExecTimeName, .1f);
73
74 capabilities.float32Performance.powerUsage =
75 ParseSystemProperty(g_Float32PerformancePowerUsageName, .1f);
76
77 capabilities.quantized8Performance.execTime =
78 ParseSystemProperty(g_Quantized8PerformanceExecTimeName, .1f);
79
80 capabilities.quantized8Performance.powerUsage =
81 ParseSystemProperty(g_Quantized8PerformancePowerUsageName, .1f);
82
83 cb(ErrorStatus::NONE, capabilities);
84 }
85 else
86 {
87 capabilities.float32Performance.execTime = 0;
88 capabilities.float32Performance.powerUsage = 0;
89 capabilities.quantized8Performance.execTime = 0;
90 capabilities.quantized8Performance.powerUsage = 0;
91
92 cb(ErrorStatus::DEVICE_UNAVAILABLE, capabilities);
93 }
94
95 return Void();
96}
97
Matteo Martincighe48bdff2018-09-03 13:50:50 +010098template <typename HalVersion>
99Return<void> ArmnnDriverImpl<HalVersion>::getSupportedOperations(
telsoa01ce3e84a2018-08-31 09:31:35 +0100100 const armnn::IRuntimePtr& runtime,
101 const DriverOptions& options,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100102 const HalModel& model,
103 HalGetSupportedOperations_cb cb)
telsoa01ce3e84a2018-08-31 09:31:35 +0100104{
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100105 ALOGV("ArmnnDriverImpl::getSupportedOperations()");
telsoa01ce3e84a2018-08-31 09:31:35 +0100106
107 vector<bool> result;
108
109 if (!runtime)
110 {
111 cb(ErrorStatus::DEVICE_UNAVAILABLE, result);
112 return Void();
113 }
114
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100115 // Run general model validation, if this doesn't pass we shouldn't analyse the model anyway.
telsoa01ce3e84a2018-08-31 09:31:35 +0100116 if (!android::nn::validateModel(model))
117 {
118 cb(ErrorStatus::INVALID_ARGUMENT, result);
119 return Void();
120 }
121
122 // Attempt to convert the model to an ArmNN input network (INetwork).
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100123 ModelToINetworkConverter<HalVersion> modelConverter(options.GetComputeDevice(),
124 model,
125 options.GetForcedUnsupportedOperations());
telsoa01ce3e84a2018-08-31 09:31:35 +0100126
127 if (modelConverter.GetConversionResult() != ConversionResult::Success
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100128 && modelConverter.GetConversionResult() != ConversionResult::UnsupportedFeature)
telsoa01ce3e84a2018-08-31 09:31:35 +0100129 {
130 cb(ErrorStatus::GENERAL_FAILURE, result);
131 return Void();
132 }
133
134 // Check each operation if it was converted successfully and copy the flags
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100135 // into the result (vector<bool>) that we need to return to Android.
telsoa01ce3e84a2018-08-31 09:31:35 +0100136 result.reserve(model.operations.size());
137 for (uint32_t operationIdx = 0; operationIdx < model.operations.size(); operationIdx++)
138 {
139 bool operationSupported = modelConverter.IsOperationSupported(operationIdx);
140 result.push_back(operationSupported);
141 }
142
143 cb(ErrorStatus::NONE, result);
144 return Void();
145}
146
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100147template <typename HalVersion>
148Return<ErrorStatus> ArmnnDriverImpl<HalVersion>::prepareModel(
telsoa01ce3e84a2018-08-31 09:31:35 +0100149 const armnn::IRuntimePtr& runtime,
150 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
151 const DriverOptions& options,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100152 const HalModel& model,
telsoa01ce3e84a2018-08-31 09:31:35 +0100153 const sp<IPreparedModelCallback>& cb,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100154 bool float32ToFloat16)
telsoa01ce3e84a2018-08-31 09:31:35 +0100155{
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100156 ALOGV("ArmnnDriverImpl::prepareModel()");
telsoa01ce3e84a2018-08-31 09:31:35 +0100157
158 if (cb.get() == nullptr)
159 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100160 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
telsoa01ce3e84a2018-08-31 09:31:35 +0100161 return ErrorStatus::INVALID_ARGUMENT;
162 }
163
164 if (!runtime)
165 {
166 return FailPrepareModel(ErrorStatus::DEVICE_UNAVAILABLE,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100167 "ArmnnDriverImpl::prepareModel: Device unavailable", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100168 }
169
170 if (!android::nn::validateModel(model))
171 {
172 return FailPrepareModel(ErrorStatus::INVALID_ARGUMENT,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100173 "ArmnnDriverImpl::prepareModel: Invalid model passed as input", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100174 }
175
176 // Deliberately ignore any unsupported operations requested by the options -
177 // at this point we're being asked to prepare a model that we've already declared support for
178 // and the operation indices may be different to those in getSupportedOperations anyway.
179 set<unsigned int> unsupportedOperations;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100180 ModelToINetworkConverter<HalVersion> modelConverter(options.GetComputeDevice(),
181 model,
182 unsupportedOperations);
telsoa01ce3e84a2018-08-31 09:31:35 +0100183
184 if (modelConverter.GetConversionResult() != ConversionResult::Success)
185 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100186 FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
187 "ArmnnDriverImpl::prepareModel: ModelToINetworkConverter failed", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100188 return ErrorStatus::NONE;
189 }
190
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100191 // Optimize the network
telsoa01ce3e84a2018-08-31 09:31:35 +0100192 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
193 armnn::OptimizerOptions OptOptions;
194 OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;
195
196 try
197 {
198 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
199 {options.GetComputeDevice()},
200 runtime->GetDeviceSpec(),
201 OptOptions);
202 }
203 catch (armnn::Exception &e)
204 {
205 stringstream message;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100206 message << "ArmnnDriverImpl::prepareModel: armnn::Exception (" << e.what() << ") caught from optimize.";
telsoa01ce3e84a2018-08-31 09:31:35 +0100207 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
208 return ErrorStatus::NONE;
209 }
210
211 // Check that the optimized network is valid.
212 if (!optNet)
213 {
214 FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100215 "ArmnnDriverImpl::prepareModel: Invalid optimized network", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100216 return ErrorStatus::NONE;
217 }
218
219 // Export the optimized network graph to a dot file if an output dump directory
220 // has been specified in the drivers' arguments.
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100221 ExportNetworkGraphToDotFile<HalModel>(*optNet, options.GetRequestInputsAndOutputsDumpDir(), model);
telsoa01ce3e84a2018-08-31 09:31:35 +0100222
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100223 // Load it into the runtime.
telsoa01ce3e84a2018-08-31 09:31:35 +0100224 armnn::NetworkId netId = 0;
225 try
226 {
227 if (runtime->LoadNetwork(netId, move(optNet)) != armnn::Status::Success)
228 {
229 return FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100230 "ArmnnDriverImpl::prepareModel: Network could not be loaded", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100231 }
232 }
233 catch (armnn::Exception& e)
234 {
235 stringstream message;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100236 message << "ArmnnDriverImpl::prepareModel: armnn::Exception (" << e.what()<< ") caught from LoadNetwork.";
telsoa01ce3e84a2018-08-31 09:31:35 +0100237 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
238 return ErrorStatus::NONE;
239 }
240
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100241 unique_ptr<ArmnnPreparedModel<HalVersion>> preparedModel(
242 new ArmnnPreparedModel<HalVersion>(
243 netId,
244 runtime.get(),
245 model,
246 options.GetRequestInputsAndOutputsDumpDir(),
247 options.IsGpuProfilingEnabled()));
telsoa01ce3e84a2018-08-31 09:31:35 +0100248
249 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
250 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
251 preparedModel->ExecuteWithDummyInputs();
252
253 if (clTunedParameters &&
254 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
255 {
256 // Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file.
257 try
258 {
259 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
260 }
261 catch (const armnn::Exception& error)
262 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100263 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
telsoa01ce3e84a2018-08-31 09:31:35 +0100264 options.GetClTunedParametersFile().c_str(), error.what());
265 }
266 }
267
268 NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel.release());
269
270 return ErrorStatus::NONE;
271}
272
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100273template <typename HalVersion>
274Return<DeviceStatus> ArmnnDriverImpl<HalVersion>::getStatus()
telsoa01ce3e84a2018-08-31 09:31:35 +0100275{
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100276 ALOGV("ArmnnDriver::getStatus()");
telsoa01ce3e84a2018-08-31 09:31:35 +0100277
278 return DeviceStatus::AVAILABLE;
279}
280
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100281// Class template specializations
282template class ArmnnDriverImpl<HalVersion_1_0>;
283
284#ifdef ARMNN_ANDROID_NN_V1_1
285template class ArmnnDriverImpl<HalVersion_1_1>;
286#endif
287
telsoa01ce3e84a2018-08-31 09:31:35 +0100288} // namespace armnn_driver