blob: dd60cc7bf31233bdd4eea9838ce188c0c4852174 [file] [log] [blame]
telsoa01ce3e84a2018-08-31 09:31:35 +01001//
John Mcloughlin7c4fc932023-04-07 16:21:49 +01002// Copyright © 2017, 2023 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"
Colm Donelan08d9a1c2020-09-09 17:56:55 +010023
Mike Kellyb5fdf382019-06-11 16:35:25 +010024#include <ValidateHal.h>
telsoa01ce3e84a2018-08-31 09:31:35 +010025#include <log/log.h>
Ryan OSheac7756cf2022-03-08 01:45:36 +000026#include <chrono>
telsoa01ce3e84a2018-08-31 09:31:35 +010027
28using namespace std;
29using namespace android;
30using namespace android::nn;
31using namespace android::hardware;
32
33namespace
34{
35
Matthew Bentham912b3622019-05-03 15:49:14 +010036void NotifyCallbackAndCheck(const sp<V1_0::IPreparedModelCallback>& callback,
Kevin Mayec1e5b82020-02-26 17:00:39 +000037 V1_0::ErrorStatus errorStatus,
Matthew Bentham912b3622019-05-03 15:49:14 +010038 const sp<V1_0::IPreparedModel>& preparedModelPtr)
telsoa01ce3e84a2018-08-31 09:31:35 +010039{
40 Return<void> returned = callback->notify(errorStatus, preparedModelPtr);
41 // This check is required, if the callback fails and it isn't checked it will bring down the service
42 if (!returned.isOk())
43 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +010044 ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
Mike Kellyb5fdf382019-06-11 16:35:25 +010045 returned.description().c_str());
telsoa01ce3e84a2018-08-31 09:31:35 +010046 }
47}
48
Kevin Mayec1e5b82020-02-26 17:00:39 +000049Return<V1_0::ErrorStatus> FailPrepareModel(V1_0::ErrorStatus error,
50 const string& message,
51 const sp<V1_0::IPreparedModelCallback>& callback)
telsoa01ce3e84a2018-08-31 09:31:35 +010052{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010053 ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str());
telsoa01ce3e84a2018-08-31 09:31:35 +010054 NotifyCallbackAndCheck(callback, error, nullptr);
55 return error;
56}
57
58} // namespace
59
60namespace armnn_driver
61{
telsoa01ce3e84a2018-08-31 09:31:35 +010062
arovir01b0717b52018-09-05 17:03:25 +010063template<typename HalPolicy>
Kevin Mayec1e5b82020-02-26 17:00:39 +000064Return<V1_0::ErrorStatus> ArmnnDriverImpl<HalPolicy>::prepareModel(
telsoa01ce3e84a2018-08-31 09:31:35 +010065 const armnn::IRuntimePtr& runtime,
66 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
67 const DriverOptions& options,
Matteo Martincighe48bdff2018-09-03 13:50:50 +010068 const HalModel& model,
Matthew Bentham912b3622019-05-03 15:49:14 +010069 const sp<V1_0::IPreparedModelCallback>& cb,
Matteo Martincighe48bdff2018-09-03 13:50:50 +010070 bool float32ToFloat16)
telsoa01ce3e84a2018-08-31 09:31:35 +010071{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010072 ALOGV("ArmnnDriverImpl::prepareModel()");
telsoa01ce3e84a2018-08-31 09:31:35 +010073
Ryan OSheac7756cf2022-03-08 01:45:36 +000074 std::chrono::time_point<std::chrono::system_clock> prepareModelTimepoint = std::chrono::system_clock::now();
75
telsoa01ce3e84a2018-08-31 09:31:35 +010076 if (cb.get() == nullptr)
77 {
Matteo Martincighe48bdff2018-09-03 13:50:50 +010078 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
Kevin Mayec1e5b82020-02-26 17:00:39 +000079 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa01ce3e84a2018-08-31 09:31:35 +010080 }
81
82 if (!runtime)
83 {
Kevin Mayec1e5b82020-02-26 17:00:39 +000084 return FailPrepareModel(V1_0::ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +010085 }
86
87 if (!android::nn::validateModel(model))
88 {
Kevin Mayec1e5b82020-02-26 17:00:39 +000089 return FailPrepareModel(V1_0::ErrorStatus::INVALID_ARGUMENT, "Invalid model passed as input", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +010090 }
91
92 // Deliberately ignore any unsupported operations requested by the options -
93 // at this point we're being asked to prepare a model that we've already declared support for
94 // and the operation indices may be different to those in getSupportedOperations anyway.
95 set<unsigned int> unsupportedOperations;
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +010096 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
97 model,
98 unsupportedOperations);
telsoa01ce3e84a2018-08-31 09:31:35 +010099
100 if (modelConverter.GetConversionResult() != ConversionResult::Success)
101 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000102 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb);
103 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100104 }
105
Sadik Armaganb3021432021-01-13 15:56:51 +0000106 // Serialize the network graph to a .armnn file if an output directory
107 // has been specified in the drivers' arguments.
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100108 std::vector<uint8_t> dataCacheData;
Sadik Armaganb3021432021-01-13 15:56:51 +0000109 auto serializedNetworkFileName =
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100110 SerializeNetwork(*modelConverter.GetINetwork(),
111 options.GetRequestInputsAndOutputsDumpDir(),
112 dataCacheData,
113 false);
Sadik Armaganb3021432021-01-13 15:56:51 +0000114
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100115 // Optimize the network
telsoa01ce3e84a2018-08-31 09:31:35 +0100116 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
John Mcloughlin7c4fc932023-04-07 16:21:49 +0100117 armnn::OptimizerOptionsOpaque OptOptions;
118 OptOptions.SetReduceFp32ToFp16(float32ToFloat16);
telsoa01ce3e84a2018-08-31 09:31:35 +0100119
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100120 armnn::BackendOptions gpuAcc("GpuAcc",
121 {
Sadik Armaganf36e10b2021-01-11 16:34:01 +0000122 { "FastMathEnabled", options.IsFastMathEnabled() },
123 { "SaveCachedNetwork", options.SaveCachedNetwork() },
Finn Williamsf5ca16c2021-02-12 14:26:23 +0000124 { "CachedNetworkFilePath", options.GetCachedNetworkFilePath() },
125 { "MLGOTuningFilePath", options.GetClMLGOTunedParametersFile() }
126
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100127 });
Finn Williamsf5ca16c2021-02-12 14:26:23 +0000128
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100129 armnn::BackendOptions cpuAcc("CpuAcc",
130 {
Matthew Sloyancd639c92021-02-11 16:57:38 +0000131 { "FastMathEnabled", options.IsFastMathEnabled() },
132 { "NumberOfThreads", options.GetNumberOfThreads() }
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100133 });
John Mcloughlin7c4fc932023-04-07 16:21:49 +0100134 OptOptions.AddModelOption(gpuAcc);
135 OptOptions.AddModelOption(cpuAcc);
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100136
jimfly0107dedda2018-10-09 12:29:41 +0100137 std::vector<std::string> errMessages;
telsoa01ce3e84a2018-08-31 09:31:35 +0100138 try
139 {
140 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100141 options.GetBackends(),
telsoa01ce3e84a2018-08-31 09:31:35 +0100142 runtime->GetDeviceSpec(),
jimfly0107dedda2018-10-09 12:29:41 +0100143 OptOptions,
144 errMessages);
telsoa01ce3e84a2018-08-31 09:31:35 +0100145 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000146 catch (std::exception &e)
telsoa01ce3e84a2018-08-31 09:31:35 +0100147 {
148 stringstream message;
Derek Lambertib9cb8442019-11-28 13:34:48 +0000149 message << "Exception (" << e.what() << ") caught from optimize.";
Kevin Mayec1e5b82020-02-26 17:00:39 +0000150 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
151 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100152 }
153
154 // Check that the optimized network is valid.
155 if (!optNet)
156 {
jimfly0107dedda2018-10-09 12:29:41 +0100157 stringstream message;
Matteo Martincigh8d50f8f2018-10-25 15:39:33 +0100158 message << "Invalid optimized network";
159 for (const string& msg : errMessages)
160 {
jimfly0107dedda2018-10-09 12:29:41 +0100161 message << "\n" << msg;
162 }
Kevin Mayec1e5b82020-02-26 17:00:39 +0000163 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
164 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100165 }
166
167 // Export the optimized network graph to a dot file if an output dump directory
168 // has been specified in the drivers' arguments.
Jim Flynn829ad302019-12-13 14:43:24 +0000169 std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet, options.GetRequestInputsAndOutputsDumpDir());
telsoa01ce3e84a2018-08-31 09:31:35 +0100170
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100171 // Load it into the runtime.
telsoa01ce3e84a2018-08-31 09:31:35 +0100172 armnn::NetworkId netId = 0;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100173 std::string msg;
174 armnn::INetworkProperties networkProperties(options.isAsyncModelExecutionEnabled(),
175 armnn::MemorySource::Undefined,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100176 armnn::MemorySource::Undefined);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100177
telsoa01ce3e84a2018-08-31 09:31:35 +0100178 try
179 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100180 if (runtime->LoadNetwork(netId, move(optNet), msg, networkProperties) != armnn::Status::Success)
telsoa01ce3e84a2018-08-31 09:31:35 +0100181 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000182 return FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Network could not be loaded", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100183 }
184 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000185 catch (std::exception& e)
telsoa01ce3e84a2018-08-31 09:31:35 +0100186 {
187 stringstream message;
Derek Lambertib9cb8442019-11-28 13:34:48 +0000188 message << "Exception (" << e.what()<< ") caught from LoadNetwork.";
Kevin Mayec1e5b82020-02-26 17:00:39 +0000189 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
190 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100191 }
192
Sadik Armaganb3021432021-01-13 15:56:51 +0000193 // Now that we have a networkId for the graph rename the exported files to use it
194 // so that we can associate the graph file and the input/output tensor exported files
195 RenameExportedFiles(serializedNetworkFileName,
196 dotGraphFileName,
197 options.GetRequestInputsAndOutputsDumpDir(),
198 netId);
Jim Flynn829ad302019-12-13 14:43:24 +0000199
Kevin Mayd5e94652019-11-07 14:02:14 +0000200 sp<ArmnnPreparedModel<HalPolicy>> preparedModel(
Mike Kellyb5fdf382019-06-11 16:35:25 +0100201 new ArmnnPreparedModel<HalPolicy>(
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100202 netId,
203 runtime.get(),
204 model,
205 options.GetRequestInputsAndOutputsDumpDir(),
Finn Williamsd8fb5402021-05-19 20:52:00 +0100206 options.IsGpuProfilingEnabled(),
Finn Williamsca3a3e02021-06-11 15:04:02 +0100207 options.isAsyncModelExecutionEnabled(),
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000208 options.getNoOfArmnnThreads(),
209 options.isImportEnabled(),
210 options.isExportEnabled()));
telsoa01ce3e84a2018-08-31 09:31:35 +0100211
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000212 if (std::find(options.GetBackends().begin(),
213 options.GetBackends().end(),
214 armnn::Compute::GpuAcc) != options.GetBackends().end())
Matthew Bentham16196e22019-04-01 17:17:58 +0100215 {
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000216 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
217 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
218 if (!preparedModel->ExecuteWithDummyInputs())
telsoa01ce3e84a2018-08-31 09:31:35 +0100219 {
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000220 return FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Network could not be executed", cb);
telsoa01ce3e84a2018-08-31 09:31:35 +0100221 }
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000222
223 if (clTunedParameters &&
224 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
telsoa01ce3e84a2018-08-31 09:31:35 +0100225 {
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000226 // Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file
227 try
228 {
229 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
230 }
231 catch (std::exception& error)
232 {
233 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
234 options.GetClTunedParametersFile().c_str(), error.what());
235 }
telsoa01ce3e84a2018-08-31 09:31:35 +0100236 }
237 }
Kevin Mayec1e5b82020-02-26 17:00:39 +0000238 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel);
telsoa01ce3e84a2018-08-31 09:31:35 +0100239
Ryan OSheac7756cf2022-03-08 01:45:36 +0000240 ALOGV("ArmnnDriverImpl::prepareModel cache timing = %lld µs", std::chrono::duration_cast<std::chrono::microseconds>
241 (std::chrono::system_clock::now() - prepareModelTimepoint).count());
242
Kevin Mayec1e5b82020-02-26 17:00:39 +0000243 return V1_0::ErrorStatus::NONE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100244}
245
arovir01b0717b52018-09-05 17:03:25 +0100246template<typename HalPolicy>
Mike Kellyb5fdf382019-06-11 16:35:25 +0100247Return<void> ArmnnDriverImpl<HalPolicy>::getSupportedOperations(const armnn::IRuntimePtr& runtime,
248 const DriverOptions& options,
249 const HalModel& model,
250 HalGetSupportedOperations_cb cb)
251{
Jim Flynn829ad302019-12-13 14:43:24 +0000252 std::stringstream ss;
253 ss << "ArmnnDriverImpl::getSupportedOperations()";
254 std::string fileName;
255 std::string timestamp;
256 if (!options.GetRequestInputsAndOutputsDumpDir().empty())
257 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100258 ss << " : "
259 << options.GetRequestInputsAndOutputsDumpDir()
260 << "/"
261 << GetFileTimestamp()
262 << "_getSupportedOperations.txt";
Jim Flynn829ad302019-12-13 14:43:24 +0000263 }
264 ALOGV(ss.str().c_str());
265
266 if (!options.GetRequestInputsAndOutputsDumpDir().empty())
267 {
268 //dump the marker file
269 std::ofstream fileStream;
270 fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
271 if (fileStream.good())
272 {
273 fileStream << timestamp << std::endl;
274 }
275 fileStream.close();
276 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100277
278 vector<bool> result;
279
280 if (!runtime)
281 {
Kevin May42477c12020-03-26 13:34:14 +0000282 cb(HalErrorStatus::DEVICE_UNAVAILABLE, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100283 return Void();
284 }
285
286 // Run general model validation, if this doesn't pass we shouldn't analyse the model anyway.
287 if (!android::nn::validateModel(model))
288 {
Kevin May42477c12020-03-26 13:34:14 +0000289 cb(HalErrorStatus::INVALID_ARGUMENT, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100290 return Void();
291 }
292
293 // Attempt to convert the model to an ArmNN input network (INetwork).
294 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
295 model,
296 options.GetForcedUnsupportedOperations());
297
298 if (modelConverter.GetConversionResult() != ConversionResult::Success
299 && modelConverter.GetConversionResult() != ConversionResult::UnsupportedFeature)
300 {
Kevin May42477c12020-03-26 13:34:14 +0000301 cb(HalErrorStatus::GENERAL_FAILURE, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100302 return Void();
303 }
304
305 // Check each operation if it was converted successfully and copy the flags
306 // into the result (vector<bool>) that we need to return to Android.
Kevin May42477c12020-03-26 13:34:14 +0000307 result.reserve(getMainModel(model).operations.size());
308 for (uint32_t operationIdx = 0;
309 operationIdx < getMainModel(model).operations.size();
310 ++operationIdx)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100311 {
312 bool operationSupported = modelConverter.IsOperationSupported(operationIdx);
313 result.push_back(operationSupported);
314 }
315
Kevin May42477c12020-03-26 13:34:14 +0000316 cb(HalErrorStatus::NONE, result);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100317 return Void();
318}
319
320template<typename HalPolicy>
Sadik Armagan188675f2021-02-12 17:16:42 +0000321Return<V1_0::DeviceStatus> ArmnnDriverImpl<HalPolicy>::getStatus()
telsoa01ce3e84a2018-08-31 09:31:35 +0100322{
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100323 ALOGV("ArmnnDriver::getStatus()");
telsoa01ce3e84a2018-08-31 09:31:35 +0100324
Sadik Armagan188675f2021-02-12 17:16:42 +0000325 return V1_0::DeviceStatus::AVAILABLE;
telsoa01ce3e84a2018-08-31 09:31:35 +0100326}
327
arovir01b0717b52018-09-05 17:03:25 +0100328///
329/// Class template specializations
330///
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100331
arovir01b0717b52018-09-05 17:03:25 +0100332template class ArmnnDriverImpl<hal_1_0::HalPolicy>;
333
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100334#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100335template class ArmnnDriverImpl<hal_1_1::HalPolicy>;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100336#endif
337
Mike Kellyb5fdf382019-06-11 16:35:25 +0100338#ifdef ARMNN_ANDROID_NN_V1_2
339template class ArmnnDriverImpl<hal_1_1::HalPolicy>;
340template class ArmnnDriverImpl<hal_1_2::HalPolicy>;
341#endif
342
Kevin May42477c12020-03-26 13:34:14 +0000343#ifdef ARMNN_ANDROID_NN_V1_3
344template class ArmnnDriverImpl<hal_1_1::HalPolicy>;
345template class ArmnnDriverImpl<hal_1_2::HalPolicy>;
346template class ArmnnDriverImpl<hal_1_3::HalPolicy>;
347#endif
348
Matteo Martincigh8d50f8f2018-10-25 15:39:33 +0100349} // namespace armnn_driver