blob: c894aef42d781fe6889d96a4e5e4d53d6aa0a549 [file] [log] [blame]
telsoa01ce3e84a2018-08-31 09:31:35 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beck93e48982018-09-05 13:05:09 +01003// SPDX-License-Identifier: MIT
telsoa01ce3e84a2018-08-31 09:31:35 +01004//
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
telsoa01ce3e84a2018-08-31 09:31:35 +010029void NotifyCallbackAndCheck(const sp<IPreparedModelCallback>& callback,
30 ErrorStatus errorStatus,
31 const sp<IPreparedModel>& preparedModelPtr)
32{
33 Return<void> returned = callback->notify(errorStatus, preparedModelPtr);
34 // This check is required, if the callback fails and it isn't checked it will bring down the service
35 if (!returned.isOk())
36 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +010037 ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
telsoa01ce3e84a2018-08-31 09:31:35 +010038 returned.description().c_str());
39 }
40}
41
42Return<ErrorStatus> FailPrepareModel(ErrorStatus error,
43 const string& message,
44 const sp<IPreparedModelCallback>& callback)
45{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010046 ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str());
telsoa01ce3e84a2018-08-31 09:31:35 +010047 NotifyCallbackAndCheck(callback, error, nullptr);
48 return error;
49}
50
51} // namespace
52
53namespace armnn_driver
54{
telsoa01ce3e84a2018-08-31 09:31:35 +010055
Matteo Martincighe48bdff2018-09-03 13:50:50 +010056template <typename HalVersion>
Matteo Martincighe48bdff2018-09-03 13:50:50 +010057Return<void> ArmnnDriverImpl<HalVersion>::getSupportedOperations(
telsoa01ce3e84a2018-08-31 09:31:35 +010058 const armnn::IRuntimePtr& runtime,
59 const DriverOptions& options,
Matteo Martincighe48bdff2018-09-03 13:50:50 +010060 const HalModel& model,
61 HalGetSupportedOperations_cb cb)
telsoa01ce3e84a2018-08-31 09:31:35 +010062{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010063 ALOGV("ArmnnDriverImpl::getSupportedOperations()");
telsoa01ce3e84a2018-08-31 09:31:35 +010064
65 vector<bool> result;
66
67 if (!runtime)
68 {
69 cb(ErrorStatus::DEVICE_UNAVAILABLE, result);
70 return Void();
71 }
72
Matteo Martincighe48bdff2018-09-03 13:50:50 +010073 // Run general model validation, if this doesn't pass we shouldn't analyse the model anyway.
telsoa01ce3e84a2018-08-31 09:31:35 +010074 if (!android::nn::validateModel(model))
75 {
76 cb(ErrorStatus::INVALID_ARGUMENT, result);
77 return Void();
78 }
79
80 // Attempt to convert the model to an ArmNN input network (INetwork).
Matteo Martincighe48bdff2018-09-03 13:50:50 +010081 ModelToINetworkConverter<HalVersion> modelConverter(options.GetComputeDevice(),
82 model,
83 options.GetForcedUnsupportedOperations());
telsoa01ce3e84a2018-08-31 09:31:35 +010084
85 if (modelConverter.GetConversionResult() != ConversionResult::Success
Matteo Martincighe48bdff2018-09-03 13:50:50 +010086 && modelConverter.GetConversionResult() != ConversionResult::UnsupportedFeature)
telsoa01ce3e84a2018-08-31 09:31:35 +010087 {
88 cb(ErrorStatus::GENERAL_FAILURE, result);
89 return Void();
90 }
91
92 // Check each operation if it was converted successfully and copy the flags
Matteo Martincighe48bdff2018-09-03 13:50:50 +010093 // into the result (vector<bool>) that we need to return to Android.
telsoa01ce3e84a2018-08-31 09:31:35 +010094 result.reserve(model.operations.size());
95 for (uint32_t operationIdx = 0; operationIdx < model.operations.size(); operationIdx++)
96 {
97 bool operationSupported = modelConverter.IsOperationSupported(operationIdx);
98 result.push_back(operationSupported);
99 }
100
101 cb(ErrorStatus::NONE, result);
102 return Void();
103}
104
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100105template <typename HalVersion>
106Return<ErrorStatus> ArmnnDriverImpl<HalVersion>::prepareModel(
telsoa01ce3e84a2018-08-31 09:31:35 +0100107 const armnn::IRuntimePtr& runtime,
108 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
109 const DriverOptions& options,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100110 const HalModel& model,
telsoa01ce3e84a2018-08-31 09:31:35 +0100111 const sp<IPreparedModelCallback>& cb,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100112 bool float32ToFloat16)
telsoa01ce3e84a2018-08-31 09:31:35 +0100113{
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100114 ALOGV("ArmnnDriverImpl::prepareModel()");
telsoa01ce3e84a2018-08-31 09:31:35 +0100115
116 if (cb.get() == nullptr)
117 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100118 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
telsoa01ce3e84a2018-08-31 09:31:35 +0100119 return ErrorStatus::INVALID_ARGUMENT;
120 }
121
122 if (!runtime)
123 {
124 return FailPrepareModel(ErrorStatus::DEVICE_UNAVAILABLE,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100125 "ArmnnDriverImpl::prepareModel: Device unavailable", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100126 }
127
128 if (!android::nn::validateModel(model))
129 {
130 return FailPrepareModel(ErrorStatus::INVALID_ARGUMENT,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100131 "ArmnnDriverImpl::prepareModel: Invalid model passed as input", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100132 }
133
134 // Deliberately ignore any unsupported operations requested by the options -
135 // at this point we're being asked to prepare a model that we've already declared support for
136 // and the operation indices may be different to those in getSupportedOperations anyway.
137 set<unsigned int> unsupportedOperations;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100138 ModelToINetworkConverter<HalVersion> modelConverter(options.GetComputeDevice(),
139 model,
140 unsupportedOperations);
telsoa01ce3e84a2018-08-31 09:31:35 +0100141
142 if (modelConverter.GetConversionResult() != ConversionResult::Success)
143 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100144 FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
145 "ArmnnDriverImpl::prepareModel: ModelToINetworkConverter failed", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100146 return ErrorStatus::NONE;
147 }
148
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100149 // Optimize the network
telsoa01ce3e84a2018-08-31 09:31:35 +0100150 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
151 armnn::OptimizerOptions OptOptions;
152 OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;
153
154 try
155 {
156 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
157 {options.GetComputeDevice()},
158 runtime->GetDeviceSpec(),
159 OptOptions);
160 }
161 catch (armnn::Exception &e)
162 {
163 stringstream message;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100164 message << "ArmnnDriverImpl::prepareModel: armnn::Exception (" << e.what() << ") caught from optimize.";
telsoa01ce3e84a2018-08-31 09:31:35 +0100165 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
166 return ErrorStatus::NONE;
167 }
168
169 // Check that the optimized network is valid.
170 if (!optNet)
171 {
172 FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100173 "ArmnnDriverImpl::prepareModel: Invalid optimized network", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100174 return ErrorStatus::NONE;
175 }
176
177 // Export the optimized network graph to a dot file if an output dump directory
178 // has been specified in the drivers' arguments.
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100179 ExportNetworkGraphToDotFile<HalModel>(*optNet, options.GetRequestInputsAndOutputsDumpDir(), model);
telsoa01ce3e84a2018-08-31 09:31:35 +0100180
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100181 // Load it into the runtime.
telsoa01ce3e84a2018-08-31 09:31:35 +0100182 armnn::NetworkId netId = 0;
183 try
184 {
185 if (runtime->LoadNetwork(netId, move(optNet)) != armnn::Status::Success)
186 {
187 return FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100188 "ArmnnDriverImpl::prepareModel: Network could not be loaded", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100189 }
190 }
191 catch (armnn::Exception& e)
192 {
193 stringstream message;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100194 message << "ArmnnDriverImpl::prepareModel: armnn::Exception (" << e.what()<< ") caught from LoadNetwork.";
telsoa01ce3e84a2018-08-31 09:31:35 +0100195 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
196 return ErrorStatus::NONE;
197 }
198
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100199 unique_ptr<ArmnnPreparedModel<HalVersion>> preparedModel(
200 new ArmnnPreparedModel<HalVersion>(
201 netId,
202 runtime.get(),
203 model,
204 options.GetRequestInputsAndOutputsDumpDir(),
205 options.IsGpuProfilingEnabled()));
telsoa01ce3e84a2018-08-31 09:31:35 +0100206
207 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
208 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
209 preparedModel->ExecuteWithDummyInputs();
210
211 if (clTunedParameters &&
212 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
213 {
214 // Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file.
215 try
216 {
217 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
218 }
219 catch (const armnn::Exception& error)
220 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100221 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
telsoa01ce3e84a2018-08-31 09:31:35 +0100222 options.GetClTunedParametersFile().c_str(), error.what());
223 }
224 }
225
226 NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel.release());
227
228 return ErrorStatus::NONE;
229}
230
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100231template <typename HalVersion>
232Return<DeviceStatus> ArmnnDriverImpl<HalVersion>::getStatus()
telsoa01ce3e84a2018-08-31 09:31:35 +0100233{
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100234 ALOGV("ArmnnDriver::getStatus()");
telsoa01ce3e84a2018-08-31 09:31:35 +0100235
236 return DeviceStatus::AVAILABLE;
237}
238
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100239// Class template specializations
240template class ArmnnDriverImpl<HalVersion_1_0>;
241
Matteo Martincigh79250ab2018-09-04 16:28:10 +0100242#if defined(ARMNN_ANDROID_NN_V1_1) // Using ::android::hardware::neuralnetworks::V1_1.
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100243template class ArmnnDriverImpl<HalVersion_1_1>;
244#endif
245
telsoa01ce3e84a2018-08-31 09:31:35 +0100246} // namespace armnn_driver