blob: 936cc6e5028a751168c40a4c7857d0597e7c45f5 [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"
telsoa01ce3e84a2018-08-31 09:31:35 +01009#include "ArmnnPreparedModel.hpp"
telsoa01ce3e84a2018-08-31 09:31:35 +010010
Kevin May42477c12020-03-26 13:34:14 +000011#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3) // Using ::android::hardware::neuralnetworks::V1_2
Mike Kellyb5fdf382019-06-11 16:35:25 +010012#include "ArmnnPreparedModel_1_2.hpp"
telsoa01ce3e84a2018-08-31 09:31:35 +010013#endif
14
Kevin May42477c12020-03-26 13:34:14 +000015#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_2
16#include "ArmnnPreparedModel_1_3.hpp"
17#endif
18
19#include "Utils.hpp"
20
Mike Kellyb5fdf382019-06-11 16:35:25 +010021#include "ModelToINetworkConverter.hpp"
22#include "SystemPropertiesUtils.hpp"
23#include <ValidateHal.h>
telsoa01ce3e84a2018-08-31 09:31:35 +010024#include <log/log.h>
25
26using namespace std;
27using namespace android;
28using namespace android::nn;
29using namespace android::hardware;
30
31namespace
32{
33
Matthew Bentham912b3622019-05-03 15:49:14 +010034void NotifyCallbackAndCheck(const sp<V1_0::IPreparedModelCallback>& callback,
Kevin Mayec1e5b82020-02-26 17:00:39 +000035 V1_0::ErrorStatus errorStatus,
Matthew Bentham912b3622019-05-03 15:49:14 +010036 const sp<V1_0::IPreparedModel>& preparedModelPtr)
telsoa01ce3e84a2018-08-31 09:31:35 +010037{
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 ",
Mike Kellyb5fdf382019-06-11 16:35:25 +010043 returned.description().c_str());
telsoa01ce3e84a2018-08-31 09:31:35 +010044 }
45}
46
Kevin Mayec1e5b82020-02-26 17:00:39 +000047Return<V1_0::ErrorStatus> FailPrepareModel(V1_0::ErrorStatus error,
48 const string& message,
49 const sp<V1_0::IPreparedModelCallback>& callback)
telsoa01ce3e84a2018-08-31 09:31:35 +010050{
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
arovir01b0717b52018-09-05 17:03:25 +010061template<typename HalPolicy>
Kevin Mayec1e5b82020-02-26 17:00:39 +000062Return<V1_0::ErrorStatus> ArmnnDriverImpl<HalPolicy>::prepareModel(
telsoa01ce3e84a2018-08-31 09:31:35 +010063 const armnn::IRuntimePtr& runtime,
64 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
65 const DriverOptions& options,
Matteo Martincighe48bdff2018-09-03 13:50:50 +010066 const HalModel& model,
Matthew Bentham912b3622019-05-03 15:49:14 +010067 const sp<V1_0::IPreparedModelCallback>& cb,
Matteo Martincighe48bdff2018-09-03 13:50:50 +010068 bool float32ToFloat16)
telsoa01ce3e84a2018-08-31 09:31:35 +010069{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010070 ALOGV("ArmnnDriverImpl::prepareModel()");
telsoa01ce3e84a2018-08-31 09:31:35 +010071
72 if (cb.get() == nullptr)
73 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +010074 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
Kevin Mayec1e5b82020-02-26 17:00:39 +000075 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa01ce3e84a2018-08-31 09:31:35 +010076 }
77
78 if (!runtime)
79 {
Kevin Mayec1e5b82020-02-26 17:00:39 +000080 return FailPrepareModel(V1_0::ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +010081 }
82
83 if (!android::nn::validateModel(model))
84 {
Kevin Mayec1e5b82020-02-26 17:00:39 +000085 return FailPrepareModel(V1_0::ErrorStatus::INVALID_ARGUMENT, "Invalid model passed as input", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +010086 }
87
88 // Deliberately ignore any unsupported operations requested by the options -
89 // at this point we're being asked to prepare a model that we've already declared support for
90 // and the operation indices may be different to those in getSupportedOperations anyway.
91 set<unsigned int> unsupportedOperations;
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +010092 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
93 model,
94 unsupportedOperations);
telsoa01ce3e84a2018-08-31 09:31:35 +010095
96 if (modelConverter.GetConversionResult() != ConversionResult::Success)
97 {
Kevin Mayec1e5b82020-02-26 17:00:39 +000098 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb);
99 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100100 }
101
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100102 // Optimize the network
telsoa01ce3e84a2018-08-31 09:31:35 +0100103 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
104 armnn::OptimizerOptions OptOptions;
105 OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;
106
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100107 armnn::BackendOptions gpuAcc("GpuAcc",
108 {
109 { "FastMathEnabled", options.IsFastMathEnabled() }
110 });
111 armnn::BackendOptions cpuAcc("CpuAcc",
112 {
113 { "FastMathEnabled", options.IsFastMathEnabled() }
114 });
115 OptOptions.m_ModelOptions.push_back(gpuAcc);
116 OptOptions.m_ModelOptions.push_back(cpuAcc);
117
jimfly0107dedda2018-10-09 12:29:41 +0100118 std::vector<std::string> errMessages;
telsoa01ce3e84a2018-08-31 09:31:35 +0100119 try
120 {
121 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100122 options.GetBackends(),
telsoa01ce3e84a2018-08-31 09:31:35 +0100123 runtime->GetDeviceSpec(),
jimfly0107dedda2018-10-09 12:29:41 +0100124 OptOptions,
125 errMessages);
telsoa01ce3e84a2018-08-31 09:31:35 +0100126 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000127 catch (std::exception &e)
telsoa01ce3e84a2018-08-31 09:31:35 +0100128 {
129 stringstream message;
Derek Lambertib9cb8442019-11-28 13:34:48 +0000130 message << "Exception (" << e.what() << ") caught from optimize.";
Kevin Mayec1e5b82020-02-26 17:00:39 +0000131 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
132 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100133 }
134
135 // Check that the optimized network is valid.
136 if (!optNet)
137 {
jimfly0107dedda2018-10-09 12:29:41 +0100138 stringstream message;
Matteo Martincigh8d50f8f2018-10-25 15:39:33 +0100139 message << "Invalid optimized network";
140 for (const string& msg : errMessages)
141 {
jimfly0107dedda2018-10-09 12:29:41 +0100142 message << "\n" << msg;
143 }
Kevin Mayec1e5b82020-02-26 17:00:39 +0000144 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
145 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100146 }
147
148 // Export the optimized network graph to a dot file if an output dump directory
149 // has been specified in the drivers' arguments.
Jim Flynn829ad302019-12-13 14:43:24 +0000150 std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet, options.GetRequestInputsAndOutputsDumpDir());
telsoa01ce3e84a2018-08-31 09:31:35 +0100151
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100152 // Load it into the runtime.
telsoa01ce3e84a2018-08-31 09:31:35 +0100153 armnn::NetworkId netId = 0;
154 try
155 {
156 if (runtime->LoadNetwork(netId, move(optNet)) != armnn::Status::Success)
157 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000158 return FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Network could not be loaded", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100159 }
160 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000161 catch (std::exception& e)
telsoa01ce3e84a2018-08-31 09:31:35 +0100162 {
163 stringstream message;
Derek Lambertib9cb8442019-11-28 13:34:48 +0000164 message << "Exception (" << e.what()<< ") caught from LoadNetwork.";
Kevin Mayec1e5b82020-02-26 17:00:39 +0000165 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
166 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100167 }
168
Jim Flynn829ad302019-12-13 14:43:24 +0000169 // Now that we have a networkId for the graph rename the dump file to use it
170 // so that we can associate the graph file and the input/output tensor dump files
171 RenameGraphDotFile(dotGraphFileName,
172 options.GetRequestInputsAndOutputsDumpDir(),
173 netId);
174
Kevin Mayd5e94652019-11-07 14:02:14 +0000175 sp<ArmnnPreparedModel<HalPolicy>> preparedModel(
Mike Kellyb5fdf382019-06-11 16:35:25 +0100176 new ArmnnPreparedModel<HalPolicy>(
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100177 netId,
178 runtime.get(),
179 model,
180 options.GetRequestInputsAndOutputsDumpDir(),
181 options.IsGpuProfilingEnabled()));
telsoa01ce3e84a2018-08-31 09:31:35 +0100182
183 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
184 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
Matthew Bentham16196e22019-04-01 17:17:58 +0100185 if (!preparedModel->ExecuteWithDummyInputs())
186 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000187 return FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Network could not be executed", cb);
Matthew Bentham16196e22019-04-01 17:17:58 +0100188 }
telsoa01ce3e84a2018-08-31 09:31:35 +0100189
190 if (clTunedParameters &&
191 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
192 {
193 // Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file.
194 try
195 {
196 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
197 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000198 catch (std::exception& error)
telsoa01ce3e84a2018-08-31 09:31:35 +0100199 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100200 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
Matteo Martincigh8d50f8f2018-10-25 15:39:33 +0100201 options.GetClTunedParametersFile().c_str(), error.what());
telsoa01ce3e84a2018-08-31 09:31:35 +0100202 }
203 }
204
Kevin Mayec1e5b82020-02-26 17:00:39 +0000205 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel);
telsoa01ce3e84a2018-08-31 09:31:35 +0100206
Kevin Mayec1e5b82020-02-26 17:00:39 +0000207 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100208}
209
arovir01b0717b52018-09-05 17:03:25 +0100210template<typename HalPolicy>
Mike Kellyb5fdf382019-06-11 16:35:25 +0100211Return<void> ArmnnDriverImpl<HalPolicy>::getSupportedOperations(const armnn::IRuntimePtr& runtime,
212 const DriverOptions& options,
213 const HalModel& model,
214 HalGetSupportedOperations_cb cb)
215{
Jim Flynn829ad302019-12-13 14:43:24 +0000216 std::stringstream ss;
217 ss << "ArmnnDriverImpl::getSupportedOperations()";
218 std::string fileName;
219 std::string timestamp;
220 if (!options.GetRequestInputsAndOutputsDumpDir().empty())
221 {
222 timestamp = GetFileTimestamp();
223 fileName = boost::str(boost::format("%1%/%2%_getSupportedOperations.txt")
224 % options.GetRequestInputsAndOutputsDumpDir()
225 % timestamp);
226 ss << " : " << fileName;
227 }
228 ALOGV(ss.str().c_str());
229
230 if (!options.GetRequestInputsAndOutputsDumpDir().empty())
231 {
232 //dump the marker file
233 std::ofstream fileStream;
234 fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
235 if (fileStream.good())
236 {
237 fileStream << timestamp << std::endl;
238 }
239 fileStream.close();
240 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100241
242 vector<bool> result;
243
244 if (!runtime)
245 {
Kevin May42477c12020-03-26 13:34:14 +0000246 cb(HalErrorStatus::DEVICE_UNAVAILABLE, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100247 return Void();
248 }
249
250 // Run general model validation, if this doesn't pass we shouldn't analyse the model anyway.
251 if (!android::nn::validateModel(model))
252 {
Kevin May42477c12020-03-26 13:34:14 +0000253 cb(HalErrorStatus::INVALID_ARGUMENT, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100254 return Void();
255 }
256
257 // Attempt to convert the model to an ArmNN input network (INetwork).
258 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
259 model,
260 options.GetForcedUnsupportedOperations());
261
262 if (modelConverter.GetConversionResult() != ConversionResult::Success
263 && modelConverter.GetConversionResult() != ConversionResult::UnsupportedFeature)
264 {
Kevin May42477c12020-03-26 13:34:14 +0000265 cb(HalErrorStatus::GENERAL_FAILURE, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100266 return Void();
267 }
268
269 // Check each operation if it was converted successfully and copy the flags
270 // into the result (vector<bool>) that we need to return to Android.
Kevin May42477c12020-03-26 13:34:14 +0000271 result.reserve(getMainModel(model).operations.size());
272 for (uint32_t operationIdx = 0;
273 operationIdx < getMainModel(model).operations.size();
274 ++operationIdx)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100275 {
276 bool operationSupported = modelConverter.IsOperationSupported(operationIdx);
277 result.push_back(operationSupported);
278 }
279
Kevin May42477c12020-03-26 13:34:14 +0000280 cb(HalErrorStatus::NONE, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100281 return Void();
282}
283
284template<typename HalPolicy>
arovir01b0717b52018-09-05 17:03:25 +0100285Return<DeviceStatus> ArmnnDriverImpl<HalPolicy>::getStatus()
telsoa01ce3e84a2018-08-31 09:31:35 +0100286{
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100287 ALOGV("ArmnnDriver::getStatus()");
telsoa01ce3e84a2018-08-31 09:31:35 +0100288
289 return DeviceStatus::AVAILABLE;
290}
291
arovir01b0717b52018-09-05 17:03:25 +0100292///
293/// Class template specializations
294///
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100295
arovir01b0717b52018-09-05 17:03:25 +0100296template class ArmnnDriverImpl<hal_1_0::HalPolicy>;
297
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100298#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100299template class ArmnnDriverImpl<hal_1_1::HalPolicy>;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100300#endif
301
Mike Kellyb5fdf382019-06-11 16:35:25 +0100302#ifdef ARMNN_ANDROID_NN_V1_2
303template class ArmnnDriverImpl<hal_1_1::HalPolicy>;
304template class ArmnnDriverImpl<hal_1_2::HalPolicy>;
305#endif
306
Kevin May42477c12020-03-26 13:34:14 +0000307#ifdef ARMNN_ANDROID_NN_V1_3
308template class ArmnnDriverImpl<hal_1_1::HalPolicy>;
309template class ArmnnDriverImpl<hal_1_2::HalPolicy>;
310template class ArmnnDriverImpl<hal_1_3::HalPolicy>;
311#endif
312
Matteo Martincigh8d50f8f2018-10-25 15:39:33 +0100313} // namespace armnn_driver