blob: 1c31384ae17681d73f7e0de6ec94fb5cfe8da22e [file] [log] [blame]
Mike Kellyb5fdf382019-06-11 16:35:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "ArmnnDriverImpl.hpp"
7#include "../ArmnnPreparedModel_1_2.hpp"
8#include "../ModelToINetworkConverter.hpp"
9#include "../SystemPropertiesUtils.hpp"
10
Sadik Armagan0a2dfab2021-10-06 16:41:44 +010011#include <armnnDeserializer/IDeserializer.hpp>
12
Mike Kellyb5fdf382019-06-11 16:35:25 +010013#include <log/log.h>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +010014#include <sys/stat.h>
Mike Kellyb5fdf382019-06-11 16:35:25 +010015
16namespace
17{
18
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +010019const char *g_RelaxedFloat32toFloat16PerformanceExecTime = "ArmNN.relaxedFloat32toFloat16Performance.execTime";
FinnWilliamsArmdf655ee2019-07-24 16:04:18 +010020const char *g_RelaxedFloat32toFloat16PerformancePowerUsage = "ArmNN.relaxedFloat32toFloat16Performance.powerUsage";
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +010021
22const char *g_OperandTypeTensorFloat32PerformanceExecTime = "Armnn.operandTypeTensorFloat32Performance.execTime";
23const char *g_OperandTypeTensorFloat32PerformancePowerUsage = "Armnn.operandTypeTensorFloat32Performance.powerUsage";
24
25const char *g_OperandTypeFloat32PerformanceExecTime = "Armnn.operandTypeFloat32Performance.execTime";
26const char *g_OperandTypeFloat32PerformancePowerUsage = "Armnn.operandTypeFloat32Performance.powerUsage";
27
28const char *g_OperandTypeTensorFloat16PerformanceExecTime = "Armnn.operandTypeTensorFloat16Performance.execTime";
29const char *g_OperandTypeTensorFloat16PerformancePowerUsage = "Armnn.operandTypeTensorFloat16Performance.powerUsage";
30
31const char *g_OperandTypeFloat16PerformanceExecTime = "Armnn.operandTypeFloat16Performance.execTime";
32const char *g_OperandTypeFloat16PerformancePowerUsage = "Armnn.operandTypeFloat16Performance.powerUsage";
33
34const char *g_OperandTypeTensorQuant8AsymmPerformanceExecTime =
35 "Armnn.operandTypeTensorQuant8AsymmPerformance.execTime";
36const char *g_OperandTypeTensorQuant8AsymmPerformancePowerUsage =
37 "Armnn.operandTypeTensorQuant8AsymmPerformance.powerUsage";
38
39const char *g_OperandTypeTensorQuant16SymmPerformanceExecTime =
40 "Armnn.operandTypeTensorQuant16SymmPerformance.execTime";
41const char *g_OperandTypeTensorQuant16SymmPerformancePowerUsage =
42 "Armnn.operandTypeTensorQuant16SymmPerformance.powerUsage";
43
Pablo Tellofb45e2f2019-10-18 16:51:57 +010044const char *g_OperandTypeTensorQuant8SymmPerformanceExecTime =
45 "Armnn.operandTypeTensorQuant8SymmPerformance.execTime";
46const char *g_OperandTypeTensorQuant8SymmPerformancePowerUsage =
47 "Armnn.operandTypeTensorQuant8SymmPerformance.powerUsage";
48
Kevin May87cb7612019-11-11 17:30:35 +000049const char *g_OperandTypeTensorQuant8SymmPerChannelPerformanceExecTime =
50 "Armnn.operandTypeTensorQuant8SymmPerChannelPerformance.execTime";
51const char *g_OperandTypeTensorQuant8SymmPerChannelPerformancePowerUsage =
52 "Armnn.operandTypeTensorQuant8SymmPerChannelPerformance.powerUsage";
53
Pablo Tellofb45e2f2019-10-18 16:51:57 +010054
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +010055const char *g_OperandTypeTensorInt32PerformanceExecTime = "Armnn.operandTypeTensorInt32Performance.execTime";
56const char *g_OperandTypeTensorInt32PerformancePowerUsage = "Armnn.operandTypeTensorInt32Performance.powerUsage";
57
58const char *g_OperandTypeInt32PerformanceExecTime = "Armnn.operandTypeInt32Performance.execTime";
59const char *g_OperandTypeInt32PerformancePowerUsage = "Armnn.operandTypeInt32Performance.powerUsage";
60
61
Sadik Armagan188675f2021-02-12 17:16:42 +000062void NotifyCallbackAndCheck(const android::sp<V1_2::IPreparedModelCallback>& callback,
Kevin Mayec1e5b82020-02-26 17:00:39 +000063 V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000064 const android::sp<V1_2::IPreparedModel>& preparedModelPtr)
Mike Kellyb5fdf382019-06-11 16:35:25 +010065{
Ferran Balaguerb2397fd2019-07-25 12:12:39 +010066 Return<void> returned = callback->notify_1_2(errorStatus, preparedModelPtr);
Mike Kellyb5fdf382019-06-11 16:35:25 +010067 // This check is required, if the callback fails and it isn't checked it will bring down the service
68 if (!returned.isOk())
69 {
70 ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
71 returned.description().c_str());
72 }
73}
74
Kevin Mayec1e5b82020-02-26 17:00:39 +000075Return<V1_0::ErrorStatus> FailPrepareModel(V1_0::ErrorStatus error,
76 const std::string& message,
Sadik Armagan188675f2021-02-12 17:16:42 +000077 const android::sp<V1_2::IPreparedModelCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +010078{
79 ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str());
80 NotifyCallbackAndCheck(callback, error, nullptr);
81 return error;
82}
83
84} // anonymous namespace
85
86namespace armnn_driver
87{
88namespace hal_1_2
89{
90
Kevin Mayec1e5b82020-02-26 17:00:39 +000091Return<V1_0::ErrorStatus> ArmnnDriverImpl::prepareArmnnModel_1_2(
92 const armnn::IRuntimePtr& runtime,
93 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
94 const DriverOptions& options,
95 const V1_2::Model& model,
Sadik Armagan0a2dfab2021-10-06 16:41:44 +010096 const android::hardware::hidl_vec<android::hardware::hidl_handle>& modelCacheHandle,
97 const android::hardware::hidl_vec<android::hardware::hidl_handle>& dataCacheHandle,
98 const HidlToken& token,
Sadik Armagan188675f2021-02-12 17:16:42 +000099 const android::sp<V1_2::IPreparedModelCallback>& cb,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000100 bool float32ToFloat16)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100101{
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100102 ALOGV("ArmnnDriverImpl::prepareArmnnModel_1_2()");
Mike Kellyb5fdf382019-06-11 16:35:25 +0100103
104 if (cb.get() == nullptr)
105 {
106 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000107 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100108 }
109
110 if (!runtime)
111 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000112 return FailPrepareModel(V1_0::ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100113 }
114
115 if (!android::nn::validateModel(model))
116 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000117 return FailPrepareModel(V1_0::ErrorStatus::INVALID_ARGUMENT, "Invalid model passed as input", cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100118 }
119
120 // Deliberately ignore any unsupported operations requested by the options -
121 // at this point we're being asked to prepare a model that we've already declared support for
122 // and the operation indices may be different to those in getSupportedOperations anyway.
123 std::set<unsigned int> unsupportedOperations;
124 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
125 model,
126 unsupportedOperations);
127
128 if (modelConverter.GetConversionResult() != ConversionResult::Success)
129 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000130 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb);
131 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100132 }
133
Sadik Armaganb3021432021-01-13 15:56:51 +0000134 // Serialize the network graph to a .armnn file if an output directory
135 // has been specified in the drivers' arguments.
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100136 std::vector<uint8_t> dataCacheData;
137 bool serializeToFile = dataCacheHandle.size() < 1 ? false : true;
Sadik Armaganb3021432021-01-13 15:56:51 +0000138 auto serializedNetworkFileName =
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100139 SerializeNetwork(*modelConverter.GetINetwork(),
140 options.GetRequestInputsAndOutputsDumpDir(),
141 dataCacheData,
142 serializeToFile);
Sadik Armaganb3021432021-01-13 15:56:51 +0000143
Mike Kellyb5fdf382019-06-11 16:35:25 +0100144 // Optimize the network
145 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
146 armnn::OptimizerOptions OptOptions;
147 OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;
Kevin Maydaf7dd02021-10-22 11:57:30 +0100148 OptOptions.m_ProfilingEnabled = options.IsGpuProfilingEnabled();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100149
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100150 int cachedFd = -1;
151 bool saveCachedNetwork = options.SaveCachedNetwork();
152
153 unsigned int numberOfCachedModelFiles = 0;
154 if (modelCacheHandle.size() > 0)
155 {
156 unsigned int index = 0;
157 for (auto& backend : options.GetBackends())
158 {
159 // modelCacheHandle size should be equal to numberOfCachedModelFiles
160 // modelCacheHandle vector should be in same order as backends
161 auto numberOfCacheFiles = GetNumberOfCacheFiles(backend);
162 if (numberOfCacheFiles > 0)
163 {
164 numberOfCachedModelFiles += numberOfCacheFiles;
165 if (modelCacheHandle[index]->numFds == 1)
166 {
167 if (backend == armnn::Compute::GpuAcc)
168 {
169 cachedFd = modelCacheHandle[index]->data[0];
170 saveCachedNetwork = true;
171 }
172 }
173 index += numberOfCachedModelFiles;
174 }
175 }
176 }
177
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100178 armnn::BackendOptions gpuAcc("GpuAcc",
179 {
Sadik Armaganf36e10b2021-01-11 16:34:01 +0000180 { "FastMathEnabled", options.IsFastMathEnabled() },
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100181 { "SaveCachedNetwork", saveCachedNetwork },
Finn Williamsf5ca16c2021-02-12 14:26:23 +0000182 { "CachedNetworkFilePath", options.GetCachedNetworkFilePath() },
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100183 { "MLGOTuningFilePath", options.GetClMLGOTunedParametersFile() },
184 { "CachedFileDescriptor", cachedFd }
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100185 });
Finn Williamsf5ca16c2021-02-12 14:26:23 +0000186
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100187 armnn::BackendOptions cpuAcc("CpuAcc",
188 {
Matthew Sloyancd639c92021-02-11 16:57:38 +0000189 { "FastMathEnabled", options.IsFastMathEnabled() },
190 { "NumberOfThreads", options.GetNumberOfThreads() }
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100191 });
192 OptOptions.m_ModelOptions.push_back(gpuAcc);
193 OptOptions.m_ModelOptions.push_back(cpuAcc);
194
Mike Kellyb5fdf382019-06-11 16:35:25 +0100195 std::vector<std::string> errMessages;
196 try
197 {
198 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
199 options.GetBackends(),
200 runtime->GetDeviceSpec(),
201 OptOptions,
202 errMessages);
203 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000204 catch (std::exception &e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100205 {
206 std::stringstream message;
Derek Lambertib9cb8442019-11-28 13:34:48 +0000207 message << "Exception (" << e.what() << ") caught from optimize.";
Kevin Mayec1e5b82020-02-26 17:00:39 +0000208 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
209 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100210 }
211
212 // Check that the optimized network is valid.
213 if (!optNet)
214 {
215 std::stringstream message;
216 message << "Invalid optimized network";
217 for (const std::string& msg : errMessages)
218 {
219 message << "\n" << msg;
220 }
Kevin Mayec1e5b82020-02-26 17:00:39 +0000221 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
222 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100223 }
224
225 // Export the optimized network graph to a dot file if an output dump directory
226 // has been specified in the drivers' arguments.
Jim Flynn829ad302019-12-13 14:43:24 +0000227 std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet,
228 options.GetRequestInputsAndOutputsDumpDir());
Mike Kellyb5fdf382019-06-11 16:35:25 +0100229
230 // Load it into the runtime.
231 armnn::NetworkId netId = 0;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100232 std::string msg;
233 armnn::INetworkProperties networkProperties(options.isAsyncModelExecutionEnabled(),
234 MemorySource::Undefined,
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100235 MemorySource::Undefined,
236 options.IsGpuProfilingEnabled());
237
238 auto numInputs = getMainModel(model).inputIndexes.size();
239 auto numOutputs = getMainModel(model).outputIndexes.size();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100240 try
241 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100242 if (runtime->LoadNetwork(netId, move(optNet), msg, networkProperties) != armnn::Status::Success)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100243 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100244 return FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, msg, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100245 }
246 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000247 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100248 {
249 std::stringstream message;
Derek Lambertib9cb8442019-11-28 13:34:48 +0000250 message << "Exception (" << e.what()<< ") caught from LoadNetwork.";
Kevin Mayec1e5b82020-02-26 17:00:39 +0000251 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
252 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100253 }
254
Sadik Armaganb3021432021-01-13 15:56:51 +0000255 // Now that we have a networkId for the graph rename the exported files to use it
256 // so that we can associate the graph file and the input/output tensor exported files
257 RenameExportedFiles(serializedNetworkFileName,
258 dotGraphFileName,
259 options.GetRequestInputsAndOutputsDumpDir(),
260 netId);
Jim Flynn829ad302019-12-13 14:43:24 +0000261
Mike Kellyb5fdf382019-06-11 16:35:25 +0100262 std::unique_ptr<ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>> preparedModel(
263 new ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>(
264 netId,
265 runtime.get(),
266 model,
267 options.GetRequestInputsAndOutputsDumpDir(),
Finn Williamsd8fb5402021-05-19 20:52:00 +0100268 options.IsGpuProfilingEnabled(),
Finn Williamsca3a3e02021-06-11 15:04:02 +0100269 options.isAsyncModelExecutionEnabled(),
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000270 options.getNoOfArmnnThreads(),
271 options.isImportEnabled(),
272 options.isExportEnabled()));
Mike Kellyb5fdf382019-06-11 16:35:25 +0100273
274 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
275 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100276 // Only run this if the GpuAcc backend has been added to options
277 if (std::find(options.GetBackends().begin(),
278 options.GetBackends().end(),
279 armnn::Compute::GpuAcc) != options.GetBackends().end())
Mike Kellyb5fdf382019-06-11 16:35:25 +0100280 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100281 if (!preparedModel->ExecuteWithDummyInputs(numInputs, numOutputs))
282 {
283 return FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Network could not be executed", cb);
284 }
285
286 if (clTunedParameters &&
287 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
288 {
289 // Now that we've done one inference the CL kernel parameters will have been tuned,
290 // so save the updated file.
291 try
292 {
293 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
294 }
295 catch (std::exception& error)
296 {
297 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
298 options.GetClTunedParametersFile().c_str(), error.what());
299 }
300 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100301 }
302
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100303 size_t hashValue = 0;
304 // Cache the model
305 if (dataCacheHandle.size() > 0)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100306 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100307 // Cache the Arm NN model, should be only 1
308 if (dataCacheHandle.size() != 1)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100309 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100310 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel.release());
311 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100312 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100313
314 if (dataCacheHandle[0]->numFds != 1)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100315 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100316 ALOGW("ArmnnDriverImpl::prepareArmnnModel_1_3: Cannot cache the data, numFds != 1.");
317 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel.release());
318 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100319 }
Sadik Armaganee6818b2021-11-05 14:41:52 +0000320
321 if (dataCacheHandle[0]->data[0] < 0)
322 {
323 ALOGW("ArmnnDriverImpl::prepareArmnnModel_1_3: Cannot cache the data, fd < 0");
324 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel.release());
325 return V1_0::ErrorStatus::NONE;
326 }
327
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100328 int dataCacheFileAccessMode = fcntl(dataCacheHandle[0]->data[0], F_GETFL) & O_ACCMODE;
329 if (dataCacheFileAccessMode != O_RDWR)
330 {
331 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_2(): Invalid Access Mode.");
332 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel.release());
333 return V1_0::ErrorStatus::NONE;
334 }
335
336 write(dataCacheHandle[0]->data[0], dataCacheData.data(), dataCacheData.size());
337 hashValue = CacheDataHandlerInstance().Hash(dataCacheData);
338 }
339
340 if (modelCacheHandle.size() > 0)
341 {
342 if (modelCacheHandle.size() != numberOfCachedModelFiles)
343 {
344 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel.release());
345 return V1_0::ErrorStatus::NONE;
346 }
347 for (uint32_t i = 0; i < modelCacheHandle.size(); ++i)
348 {
349 if (modelCacheHandle[i]->numFds == 1)
350 {
351 int modelCacheFileAccessMode = fcntl(modelCacheHandle[i]->data[0], F_GETFL) & O_ACCMODE;
352 if (modelCacheFileAccessMode != O_RDONLY)
353 {
354 struct stat statBuffer;
355 if (fstat(modelCacheHandle[i]->data[0], &statBuffer) == 0)
356 {
357 long modelDataSize = statBuffer.st_size;
358 if (modelDataSize > 0)
359 {
360 std::vector <uint8_t> modelData(modelDataSize);
361 pread(modelCacheHandle[i]->data[0], modelData.data(), modelData.size(), 0);
362 hashValue ^= CacheDataHandlerInstance().Hash(modelData);
363 }
364 }
365 }
366 }
367 }
368 }
369 if (hashValue != 0)
370 {
371 CacheDataHandlerInstance().Register(token, hashValue, dataCacheData.size());
Mike Kellyb5fdf382019-06-11 16:35:25 +0100372 }
373
Kevin Mayec1e5b82020-02-26 17:00:39 +0000374 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel.release());
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100375 return V1_0::ErrorStatus::NONE;
376}
Mike Kellyb5fdf382019-06-11 16:35:25 +0100377
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100378Return<V1_0::ErrorStatus> ArmnnDriverImpl::prepareModelFromCache(
379 const armnn::IRuntimePtr& runtime,
380 const DriverOptions& options,
381 const android::hardware::hidl_vec<android::hardware::hidl_handle>& modelCacheHandle,
382 const android::hardware::hidl_vec<android::hardware::hidl_handle>& dataCacheHandle,
383 const HidlToken& token,
384 const android::sp<V1_2::IPreparedModelCallback>& cb,
385 bool float32ToFloat16)
386{
387 ALOGV("ArmnnDriverImpl::prepareModelFromCache()");
388
389 if (cb.get() == nullptr)
390 {
391 ALOGW("ArmnnDriverImpl::prepareModelFromCache: Invalid callback passed to prepareModel");
392 return V1_0::ErrorStatus::INVALID_ARGUMENT;
393 }
394
395 if (!runtime)
396 {
397 return FailPrepareModel(V1_0::ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb);
398 }
399
400 if (token.size() != ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN)
401 {
402 FailPrepareModel(V1_0::ErrorStatus::INVALID_ARGUMENT, "Invalid token passed!", cb);
403 return V1_0::ErrorStatus::INVALID_ARGUMENT;
404 }
405
406 // DataCacheHandle size should always be 1
407 // Arm NN model
408 if (dataCacheHandle.size() != 1)
409 {
410 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "No data cache!", cb);
411 return V1_0::ErrorStatus::GENERAL_FAILURE;
412 }
413
414 // Check if model files cached they match the expected value
415 unsigned int numberOfCachedModelFiles = 0;
416 for (auto& backend : options.GetBackends())
417 {
418 numberOfCachedModelFiles += GetNumberOfCacheFiles(backend);
419 }
420 if (modelCacheHandle.size() != numberOfCachedModelFiles)
421 {
422 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Invalid model cache!", cb);
423 return V1_0::ErrorStatus::GENERAL_FAILURE;
424 }
425
426 if (dataCacheHandle[0]->numFds != 1)
427 {
428 ALOGW("ArmnnDriverImpl::prepareModelFromCache: Cannot read from the cache data, numFds != 1.");
429 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "No data cache!", cb);
430 return V1_0::ErrorStatus::GENERAL_FAILURE;
431 }
432
Sadik Armaganee6818b2021-11-05 14:41:52 +0000433 if (dataCacheHandle[0]->data[0] < 0)
434 {
435 ALOGW("ArmnnDriverImpl::prepareModelFromCache: Cannot read from the cache data, fd < 0");
436 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "No data cache!", cb);
437 return V1_0::ErrorStatus::GENERAL_FAILURE;
438 }
439
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100440 int dataCacheFileAccessMode = fcntl(dataCacheHandle[0]->data[0], F_GETFL) & O_ACCMODE;
441 if (dataCacheFileAccessMode != O_RDWR)
442 {
443 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Invalid Access Mode!", cb);
444 return V1_0::ErrorStatus::GENERAL_FAILURE;
445 }
446
447 auto dataSize = CacheDataHandlerInstance().GetCacheSize(token);
448 if (dataSize == 0)
449 {
450 ALOGW("ArmnnDriverImpl::prepareModelFromCache: Invalid data to deserialize!");
451 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Invalid data to deserialize!", cb);
452 return V1_0::ErrorStatus::GENERAL_FAILURE;
453 }
454
455 int offset = 0;
456 {
457 struct stat statBuffer;
458 if (fstat(dataCacheHandle[0]->data[0], &statBuffer) == 0)
459 {
460 unsigned long bufferSize = statBuffer.st_size;
Sadik Armaganee6818b2021-11-05 14:41:52 +0000461 if (bufferSize != dataSize)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100462 {
463 ALOGW("ArmnnDriverImpl::prepareModelFromCache: Invalid data to deserialize!");
464 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Invalid data to deserialize!", cb);
465 return V1_0::ErrorStatus::GENERAL_FAILURE;
466 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100467 }
468 }
469 std::vector<uint8_t> dataCacheData(dataSize);
470 pread(dataCacheHandle[0]->data[0], dataCacheData.data(), dataCacheData.size(), offset);
471 auto hashValue = CacheDataHandlerInstance().Hash(dataCacheData);
472
473 int gpuAccCachedFd = -1;
474 bool saveCachedNetwork = false;
475 if (modelCacheHandle.size() > 0)
476 {
477 unsigned int index = 0;
478 for (auto& backend : options.GetBackends())
479 {
480 // modelCacheHandle size should be equal to numberOfCachedModelFiles
481 // modelCacheHandle vector should be in same order as backends
482 auto numberOfCacheFiles = GetNumberOfCacheFiles(backend);
483 if (numberOfCacheFiles > 0)
484 {
485 if (modelCacheHandle[index]->numFds != 1)
486 {
487 ALOGW("ArmnnDriverImpl::prepareModelFromCache: Cannot read from the model cache, numFds != 1.");
488 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE,
489 "Cannot read from the model cache, numFds != 1.", cb);
490 return V1_0::ErrorStatus::GENERAL_FAILURE;
491 }
492 auto cachedFd = modelCacheHandle[index]->data[0];
493
494 int modelCacheFileAccessMode = fcntl(cachedFd, F_GETFL) & O_ACCMODE;
495 if (modelCacheFileAccessMode != O_RDWR)
496 {
497 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Invalid Access Mode!", cb);
498 return V1_0::ErrorStatus::GENERAL_FAILURE;
499 }
500
501 struct stat statBuffer;
502 if (cachedFd != -1 && fstat(cachedFd, &statBuffer) == 0)
503 {
504 long modelDataSize = statBuffer.st_size;
Sadik Armaganee6818b2021-11-05 14:41:52 +0000505 if (modelDataSize <= 0)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100506 {
Sadik Armaganee6818b2021-11-05 14:41:52 +0000507 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "Wrong cached model size!", cb);
508 return V1_0::ErrorStatus::NONE;
509 }
510 std::vector<uint8_t> modelData(modelDataSize);
511 pread(cachedFd, modelData.data(), modelData.size(), 0);
512 hashValue ^= CacheDataHandlerInstance().Hash(modelData);
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100513
Sadik Armaganee6818b2021-11-05 14:41:52 +0000514 // For GpuAcc numberOfCachedFiles is 1
515 if (backend == armnn::Compute::GpuAcc)
516 {
517 gpuAccCachedFd = cachedFd;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100518 }
519 }
520 index += numberOfCacheFiles;
521 }
522 }
523 }
524
Sadik Armaganee6818b2021-11-05 14:41:52 +0000525 if (!CacheDataHandlerInstance().Validate(token, hashValue, dataCacheData.size()))
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100526 {
527 ALOGW("ArmnnDriverImpl::prepareModelFromCache: ValidateHash() failed!");
528 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, "ValidateHash Failed!", cb);
529 return V1_0::ErrorStatus::GENERAL_FAILURE;
530 }
531
532 // Deserialize the network..
Sadik Armaganee6818b2021-11-05 14:41:52 +0000533 armnn::INetworkPtr network = armnn::INetworkPtr(nullptr, [](armnn::INetwork*){});
534 try
535 {
536 network = armnnDeserializer::IDeserializer::Create()->CreateNetworkFromBinary(dataCacheData);
537 }
538 catch (std::exception& e)
539 {
540 std::stringstream message;
541 message << "Exception (" << e.what() << ") caught from Deserializer.";
542 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
543 return V1_0::ErrorStatus::GENERAL_FAILURE;
544 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100545
546 // Optimize the network
547 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
548 armnn::OptimizerOptions OptOptions;
549 OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;
550 OptOptions.m_ProfilingEnabled = options.IsGpuProfilingEnabled();
551
552 armnn::BackendOptions gpuAcc("GpuAcc",
553 {
554 {"FastMathEnabled", options.IsFastMathEnabled()},
555 {"SaveCachedNetwork", saveCachedNetwork},
556 {"CachedNetworkFilePath", options.GetCachedNetworkFilePath()},
557 {"MLGOTuningFilePath", options.GetClMLGOTunedParametersFile()},
558 {"CachedFileDescriptor", gpuAccCachedFd}
559 });
560
561 armnn::BackendOptions cpuAcc("CpuAcc",
562 {
563 {"FastMathEnabled", options.IsFastMathEnabled()},
564 {"NumberOfThreads", options.GetNumberOfThreads()}
565 });
566 OptOptions.m_ModelOptions.push_back(gpuAcc);
567 OptOptions.m_ModelOptions.push_back(cpuAcc);
568
569 std::vector<std::string> errMessages;
570 try
571 {
572 optNet = armnn::Optimize(*network.get(),
573 options.GetBackends(),
574 runtime->GetDeviceSpec(),
575 OptOptions,
576 errMessages);
577 }
578 catch (std::exception& e)
579 {
580 std::stringstream message;
581 message << "Exception (" << e.what() << ") caught from optimize.";
582 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
583 return V1_0::ErrorStatus::NONE;
584 }
585
586 // Check that the optimized network is valid.
587 if (!optNet)
588 {
589 std::stringstream message;
590 message << "Invalid optimized network";
591 for (const std::string& msg : errMessages)
592 {
593 message << "\n" << msg;
594 }
595 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
596 return V1_0::ErrorStatus::NONE;
597 }
598
599 // Export the optimized network graph to a dot file if an output dump directory
600 // has been specified in the drivers' arguments.
601 std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet,
602 options.GetRequestInputsAndOutputsDumpDir());
603
604 // Load it into the runtime.
605 armnn::NetworkId netId = 0;
606 std::string msg;
607 armnn::INetworkProperties networkProperties(options.isAsyncModelExecutionEnabled(),
608 MemorySource::Undefined,
609 MemorySource::Undefined,
610 options.IsGpuProfilingEnabled());
611
612 try
613 {
614 if (runtime->LoadNetwork(netId, move(optNet), msg, networkProperties) != armnn::Status::Success)
615 {
616 return FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, msg, cb);
617 }
618 }
619 catch (std::exception& e)
620 {
621 std::stringstream message;
622 message << "Exception (" << e.what() << ") caught from LoadNetwork.";
623 FailPrepareModel(V1_0::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
624 return V1_0::ErrorStatus::NONE;
625 }
626
627 std::unique_ptr<ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>> preparedModel(
628 new ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>(
629 netId,
630 runtime.get(),
631 options.GetRequestInputsAndOutputsDumpDir(),
632 options.IsGpuProfilingEnabled(),
633 options.isAsyncModelExecutionEnabled(),
634 options.getNoOfArmnnThreads(),
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000635 options.isImportEnabled(),
636 options.isExportEnabled(),
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100637 true));
638
639 NotifyCallbackAndCheck(cb, V1_0::ErrorStatus::NONE, preparedModel.release());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000640 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100641}
642
643Return<void> ArmnnDriverImpl::getCapabilities_1_2(const armnn::IRuntimePtr& runtime,
644 V1_2::IDevice::getCapabilities_1_2_cb cb)
645{
646 ALOGV("hal_1_2::ArmnnDriverImpl::getCapabilities()");
647
648 V1_2::Capabilities capabilities;
649
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100650 float defaultValue = .1f;
651
Mike Kellyb5fdf382019-06-11 16:35:25 +0100652 if (runtime)
653 {
654 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime =
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100655 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, defaultValue);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100656
Kevin May2eaa1192020-04-15 16:50:57 +0100657 capabilities.relaxedFloat32toFloat16PerformanceScalar.powerUsage =
658 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformancePowerUsage, defaultValue);
659
660 capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime =
661 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, defaultValue);
662
FinnWilliamsArmdf655ee2019-07-24 16:04:18 +0100663 capabilities.relaxedFloat32toFloat16PerformanceTensor.powerUsage =
664 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformancePowerUsage, defaultValue);
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100665
666 // Set the base value for all operand types
Sadik Armagan188675f2021-02-12 17:16:42 +0000667 #if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S)
Kevin Mayec1e5b82020-02-26 17:00:39 +0000668 capabilities.operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_2>({FLT_MAX, FLT_MAX});
669 #else
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100670 capabilities.operandPerformance = nonExtensionOperandPerformance({FLT_MAX, FLT_MAX});
Kevin Mayec1e5b82020-02-26 17:00:39 +0000671 #endif
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100672
673 // Load supported operand types
Kevin Mayec1e5b82020-02-26 17:00:39 +0000674 update(&capabilities.operandPerformance, V1_2::OperandType::TENSOR_FLOAT32,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100675 {
676 .execTime = ParseSystemProperty(g_OperandTypeTensorFloat32PerformanceExecTime, defaultValue),
677 .powerUsage = ParseSystemProperty(g_OperandTypeTensorFloat32PerformancePowerUsage, defaultValue)
678 });
679
Kevin Mayec1e5b82020-02-26 17:00:39 +0000680 update(&capabilities.operandPerformance, V1_2::OperandType::FLOAT32,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100681 {
682 .execTime = ParseSystemProperty(g_OperandTypeFloat32PerformanceExecTime, defaultValue),
683 .powerUsage = ParseSystemProperty(g_OperandTypeFloat32PerformancePowerUsage, defaultValue)
684 });
685
Kevin Mayec1e5b82020-02-26 17:00:39 +0000686 update(&capabilities.operandPerformance, V1_2::OperandType::TENSOR_FLOAT16,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100687 {
688 .execTime = ParseSystemProperty(g_OperandTypeTensorFloat16PerformanceExecTime, defaultValue),
689 .powerUsage = ParseSystemProperty(g_OperandTypeTensorFloat16PerformancePowerUsage, defaultValue)
690 });
691
Kevin Mayec1e5b82020-02-26 17:00:39 +0000692 update(&capabilities.operandPerformance, V1_2::OperandType::FLOAT16,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100693 {
694 .execTime = ParseSystemProperty(g_OperandTypeFloat16PerformanceExecTime, defaultValue),
695 .powerUsage = ParseSystemProperty(g_OperandTypeFloat16PerformancePowerUsage, defaultValue)
696 });
697
Kevin Mayec1e5b82020-02-26 17:00:39 +0000698 update(&capabilities.operandPerformance, V1_2::OperandType::TENSOR_QUANT8_ASYMM,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100699 {
700 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmPerformanceExecTime, defaultValue),
701 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmPerformancePowerUsage, defaultValue)
702 });
703
Kevin Mayec1e5b82020-02-26 17:00:39 +0000704 update(&capabilities.operandPerformance, V1_2::OperandType::TENSOR_QUANT8_SYMM,
Pablo Tellofb45e2f2019-10-18 16:51:57 +0100705 {
706 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerformanceExecTime, defaultValue),
707 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerformancePowerUsage, defaultValue)
708 });
709
Kevin Mayec1e5b82020-02-26 17:00:39 +0000710 update(&capabilities.operandPerformance, V1_2::OperandType::TENSOR_QUANT16_SYMM,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100711 {
712 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant16SymmPerformanceExecTime, defaultValue),
713 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant16SymmPerformancePowerUsage, defaultValue)
714 });
715
Kevin Mayec1e5b82020-02-26 17:00:39 +0000716 update(&capabilities.operandPerformance, V1_2::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL,
Kevin May87cb7612019-11-11 17:30:35 +0000717 {
718 .execTime =
719 ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerChannelPerformanceExecTime, defaultValue),
720 .powerUsage =
721 ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerChannelPerformancePowerUsage, defaultValue)
722 });
723
Kevin Mayec1e5b82020-02-26 17:00:39 +0000724 update(&capabilities.operandPerformance, V1_2::OperandType::TENSOR_INT32,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100725 {
726 .execTime = ParseSystemProperty(g_OperandTypeTensorInt32PerformanceExecTime, defaultValue),
727 .powerUsage = ParseSystemProperty(g_OperandTypeTensorInt32PerformancePowerUsage, defaultValue)
728 });
729
Kevin Mayec1e5b82020-02-26 17:00:39 +0000730 update(&capabilities.operandPerformance, V1_2::OperandType::INT32,
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100731 {
732 .execTime = ParseSystemProperty(g_OperandTypeInt32PerformanceExecTime, defaultValue),
733 .powerUsage = ParseSystemProperty(g_OperandTypeInt32PerformancePowerUsage, defaultValue)
734 });
Mike Kellyb5fdf382019-06-11 16:35:25 +0100735
Kevin Mayec1e5b82020-02-26 17:00:39 +0000736 cb(V1_0::ErrorStatus::NONE, capabilities);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100737 }
738 else
739 {
Kevin May2eaa1192020-04-15 16:50:57 +0100740 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime = 0;
741 capabilities.relaxedFloat32toFloat16PerformanceScalar.powerUsage = 0;
742 capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime = 0;
743 capabilities.relaxedFloat32toFloat16PerformanceTensor.powerUsage = 0;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100744
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100745 // Set the base value for all operand types
Sadik Armagan188675f2021-02-12 17:16:42 +0000746 #if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S)
Kevin Mayec1e5b82020-02-26 17:00:39 +0000747 capabilities.operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_2>({0.f, 0.0f});
748 #else
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100749 capabilities.operandPerformance = nonExtensionOperandPerformance({0.f, 0.0f});
Kevin Mayec1e5b82020-02-26 17:00:39 +0000750 #endif
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100751
Kevin Mayec1e5b82020-02-26 17:00:39 +0000752 cb(V1_0::ErrorStatus::DEVICE_UNAVAILABLE, capabilities);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100753 }
754
755 return Void();
756}
757
758} // namespace hal_1_2
Kevin Mayec1e5b82020-02-26 17:00:39 +0000759} // namespace armnn_driver