blob: ec176d591c371f6900427287583e5f507631cbba [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
John Mcloughlin7c4fc932023-04-07 16:21:49 +01002// Copyright © 2020, 2023 Arm Ltd. All rights reserved.
Kevin May42477c12020-03-26 13:34:14 +00003// SPDX-License-Identifier: MIT
4//
5
6#include "ArmnnDriverImpl.hpp"
7#include "../ArmnnPreparedModel_1_3.hpp"
8#include "../ModelToINetworkConverter.hpp"
9#include "../SystemPropertiesUtils.hpp"
10
Sadik Armagan0a2dfab2021-10-06 16:41:44 +010011#include <armnnDeserializer/IDeserializer.hpp>
12
Kevin May42477c12020-03-26 13:34:14 +000013#include <log/log.h>
14
Sadik Armagan0a2dfab2021-10-06 16:41:44 +010015#include <sys/stat.h>
Ryan OSheac7756cf2022-03-08 01:45:36 +000016#include <chrono>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +010017
Kevin May42477c12020-03-26 13:34:14 +000018namespace
19{
Kevin May42477c12020-03-26 13:34:14 +000020const char *g_RelaxedFloat32toFloat16PerformanceExecTime = "ArmNN.relaxedFloat32toFloat16Performance.execTime";
21const char *g_RelaxedFloat32toFloat16PerformancePowerUsage = "ArmNN.relaxedFloat32toFloat16Performance.powerUsage";
22
Kevin May2eaa1192020-04-15 16:50:57 +010023const char *g_ifPerformanceExecTime = "ArmNN.ifPerformance.execTime";
24const char *g_ifPerformancePowerUsage = "ArmNN.ifPerformance.powerUsage";
25
26const char *g_whilePerformanceExecTime = "ArmNN.whilePerformance.execTime";
27const char *g_whilePerformancePowerUsage = "ArmNN.whilePerformance.powerUsage";
28
Kevin May42477c12020-03-26 13:34:14 +000029const char *g_OperandTypeTensorFloat32PerformanceExecTime = "Armnn.operandTypeTensorFloat32Performance.execTime";
30const char *g_OperandTypeTensorFloat32PerformancePowerUsage = "Armnn.operandTypeTensorFloat32Performance.powerUsage";
31
32const char *g_OperandTypeFloat32PerformanceExecTime = "Armnn.operandTypeFloat32Performance.execTime";
33const char *g_OperandTypeFloat32PerformancePowerUsage = "Armnn.operandTypeFloat32Performance.powerUsage";
34
35const char *g_OperandTypeTensorFloat16PerformanceExecTime = "Armnn.operandTypeTensorFloat16Performance.execTime";
36const char *g_OperandTypeTensorFloat16PerformancePowerUsage = "Armnn.operandTypeTensorFloat16Performance.powerUsage";
37
38const char *g_OperandTypeFloat16PerformanceExecTime = "Armnn.operandTypeFloat16Performance.execTime";
39const char *g_OperandTypeFloat16PerformancePowerUsage = "Armnn.operandTypeFloat16Performance.powerUsage";
40
41const char *g_OperandTypeTensorQuant8AsymmPerformanceExecTime =
42 "Armnn.operandTypeTensorQuant8AsymmPerformance.execTime";
43const char *g_OperandTypeTensorQuant8AsymmPerformancePowerUsage =
44 "Armnn.operandTypeTensorQuant8AsymmPerformance.powerUsage";
45
46const char *g_OperandTypeTensorQuant8AsymmSignedPerformanceExecTime =
47 "Armnn.operandTypeTensorQuant8AsymmSignedPerformance.execTime";
48const char *g_OperandTypeTensorQuant8AsymmSignedPerformancePowerUsage =
49 "Armnn.operandTypeTensorQuant8AsymmSignedPerformance.powerUsage";
50
51const char *g_OperandTypeTensorQuant16SymmPerformanceExecTime =
52 "Armnn.operandTypeTensorQuant16SymmPerformance.execTime";
53const char *g_OperandTypeTensorQuant16SymmPerformancePowerUsage =
54 "Armnn.operandTypeTensorQuant16SymmPerformance.powerUsage";
55
56const char *g_OperandTypeTensorQuant8SymmPerformanceExecTime =
57 "Armnn.operandTypeTensorQuant8SymmPerformance.execTime";
58const char *g_OperandTypeTensorQuant8SymmPerformancePowerUsage =
59 "Armnn.operandTypeTensorQuant8SymmPerformance.powerUsage";
60
61const char *g_OperandTypeTensorQuant8SymmPerChannelPerformanceExecTime =
62 "Armnn.operandTypeTensorQuant8SymmPerChannelPerformance.execTime";
63const char *g_OperandTypeTensorQuant8SymmPerChannelPerformancePowerUsage =
64 "Armnn.operandTypeTensorQuant8SymmPerChannelPerformance.powerUsage";
65
66
67const char *g_OperandTypeTensorInt32PerformanceExecTime = "Armnn.operandTypeTensorInt32Performance.execTime";
68const char *g_OperandTypeTensorInt32PerformancePowerUsage = "Armnn.operandTypeTensorInt32Performance.powerUsage";
69
70const char *g_OperandTypeInt32PerformanceExecTime = "Armnn.operandTypeInt32Performance.execTime";
71const char *g_OperandTypeInt32PerformancePowerUsage = "Armnn.operandTypeInt32Performance.powerUsage";
72
73
Sadik Armagan188675f2021-02-12 17:16:42 +000074void NotifyCallbackAndCheck(const android::sp<V1_3::IPreparedModelCallback>& callback,
Kevin May42477c12020-03-26 13:34:14 +000075 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000076 const android::sp<V1_3::IPreparedModel>& preparedModelPtr)
Kevin May42477c12020-03-26 13:34:14 +000077{
78 Return<void> returned = callback->notify_1_3(errorStatus, preparedModelPtr);
79 // This check is required, if the callback fails and it isn't checked it will bring down the service
80 if (!returned.isOk())
81 {
82 ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
83 returned.description().c_str());
84 }
85}
86
87Return<V1_3::ErrorStatus> FailPrepareModel(V1_3::ErrorStatus error,
88 const std::string& message,
Sadik Armagan188675f2021-02-12 17:16:42 +000089 const android::sp<V1_3::IPreparedModelCallback>& callback)
Kevin May42477c12020-03-26 13:34:14 +000090{
91 ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str());
92 NotifyCallbackAndCheck(callback, error, nullptr);
93 return error;
94}
95
96} // anonymous namespace
97
98namespace armnn_driver
99{
100namespace hal_1_3
101{
102
103Return<V1_3::ErrorStatus> ArmnnDriverImpl::prepareArmnnModel_1_3(
104 const armnn::IRuntimePtr& runtime,
105 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
106 const DriverOptions& options,
107 const V1_3::Model& model,
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100108 const android::hardware::hidl_vec<android::hardware::hidl_handle>& modelCacheHandle,
109 const android::hardware::hidl_vec<android::hardware::hidl_handle>& dataCacheHandle,
110 const HidlToken& token,
Sadik Armagan188675f2021-02-12 17:16:42 +0000111 const android::sp<V1_3::IPreparedModelCallback>& cb,
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100112 bool float32ToFloat16,
113 V1_3::Priority priority)
Kevin May42477c12020-03-26 13:34:14 +0000114{
115 ALOGV("ArmnnDriverImpl::prepareArmnnModel_1_3()");
116
Ryan OSheac7756cf2022-03-08 01:45:36 +0000117 std::chrono::time_point<std::chrono::system_clock> prepareModelTimepoint = std::chrono::system_clock::now();
118
Kevin May42477c12020-03-26 13:34:14 +0000119 if (cb.get() == nullptr)
120 {
121 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
122 return V1_3::ErrorStatus::INVALID_ARGUMENT;
123 }
124
125 if (!runtime)
126 {
127 return FailPrepareModel(V1_3::ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb);
128 }
129
130 if (!android::nn::validateModel(model))
131 {
132 return FailPrepareModel(V1_3::ErrorStatus::INVALID_ARGUMENT, "Invalid model passed as input", cb);
133 }
134
135 // Deliberately ignore any unsupported operations requested by the options -
136 // at this point we're being asked to prepare a model that we've already declared support for
137 // and the operation indices may be different to those in getSupportedOperations anyway.
138 std::set<unsigned int> unsupportedOperations;
139 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
140 model,
141 unsupportedOperations);
142
143 if (modelConverter.GetConversionResult() != ConversionResult::Success)
144 {
145 FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb);
146 return V1_3::ErrorStatus::NONE;
147 }
148
Sadik Armaganb3021432021-01-13 15:56:51 +0000149 // Serialize the network graph to a .armnn file if an output directory
150 // has been specified in the drivers' arguments.
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100151 std::vector<uint8_t> dataCacheData;
152 bool serializeToFile = dataCacheHandle.size() < 1 ? false : true;
Sadik Armaganb3021432021-01-13 15:56:51 +0000153 auto serializedNetworkFileName =
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100154 SerializeNetwork(*modelConverter.GetINetwork(),
155 options.GetRequestInputsAndOutputsDumpDir(),
156 dataCacheData,
157 serializeToFile);
Sadik Armaganb3021432021-01-13 15:56:51 +0000158
Kevin May42477c12020-03-26 13:34:14 +0000159 // Optimize the network
160 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
John Mcloughlin7c4fc932023-04-07 16:21:49 +0100161 armnn::OptimizerOptionsOpaque OptOptions;
162 OptOptions.SetReduceFp32ToFp16(float32ToFloat16);
163 OptOptions.SetProfilingEnabled(options.IsGpuProfilingEnabled());
Kevin May42477c12020-03-26 13:34:14 +0000164
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100165 int cachedFd = -1;
166 bool saveCachedNetwork = options.SaveCachedNetwork();
167
168 unsigned int numberOfCachedModelFiles = 0;
169 if (modelCacheHandle.size() > 0)
170 {
171 unsigned int index = 0;
172 for (auto& backend : options.GetBackends())
173 {
174 // modelCacheHandle size should be equal to numberOfCachedModelFiles
175 // modelCacheHandle vector should be in same order as backends
176 auto numberOfCacheFiles = GetNumberOfCacheFiles(backend);
177 if (numberOfCacheFiles > 0)
178 {
179 numberOfCachedModelFiles += numberOfCacheFiles;
180 if (modelCacheHandle[index]->numFds == 1)
181 {
182 // For GpuAcc numberOfCachedFiles is 1
183 if (backend == armnn::Compute::GpuAcc)
184 {
185 cachedFd = modelCacheHandle[index]->data[0];
186 saveCachedNetwork = true;
187 }
188 }
189 index += numberOfCachedModelFiles;
190 }
191 }
192 }
193
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100194 armnn::BackendOptions gpuAcc("GpuAcc",
195 {
Sadik Armaganf36e10b2021-01-11 16:34:01 +0000196 { "FastMathEnabled", options.IsFastMathEnabled() },
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100197 { "SaveCachedNetwork", saveCachedNetwork },
Finn Williamsf5ca16c2021-02-12 14:26:23 +0000198 { "CachedNetworkFilePath", options.GetCachedNetworkFilePath() },
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100199 { "MLGOTuningFilePath", options.GetClMLGOTunedParametersFile() },
200 { "CachedFileDescriptor", cachedFd }
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100201 });
Finn Williamsf5ca16c2021-02-12 14:26:23 +0000202
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100203 armnn::BackendOptions cpuAcc("CpuAcc",
204 {
Matthew Sloyancd639c92021-02-11 16:57:38 +0000205 { "FastMathEnabled", options.IsFastMathEnabled() },
206 { "NumberOfThreads", options.GetNumberOfThreads() }
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100207 });
John Mcloughlin7c4fc932023-04-07 16:21:49 +0100208 OptOptions.AddModelOption(gpuAcc);
209 OptOptions.AddModelOption(cpuAcc);
Mike Kelly7ed56dd2020-09-30 20:22:56 +0100210
Kevin May42477c12020-03-26 13:34:14 +0000211 std::vector<std::string> errMessages;
212 try
213 {
214 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
215 options.GetBackends(),
216 runtime->GetDeviceSpec(),
217 OptOptions,
218 errMessages);
219 }
220 catch (std::exception& e)
221 {
222 std::stringstream message;
223 message << "Exception (" << e.what() << ") caught from optimize.";
224 FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
225 return V1_3::ErrorStatus::NONE;
226 }
227
228 // Check that the optimized network is valid.
229 if (!optNet)
230 {
231 std::stringstream message;
232 message << "Invalid optimized network";
233 for (const std::string& msg : errMessages)
234 {
235 message << "\n" << msg;
236 }
237 FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
238 return V1_3::ErrorStatus::NONE;
239 }
240
241 // Export the optimized network graph to a dot file if an output dump directory
242 // has been specified in the drivers' arguments.
243 std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet,
244 options.GetRequestInputsAndOutputsDumpDir());
245
246 // Load it into the runtime.
247 armnn::NetworkId netId = 0;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100248 std::string msg;
249 armnn::INetworkProperties networkProperties(options.isAsyncModelExecutionEnabled(),
250 MemorySource::Undefined,
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100251 MemorySource::Undefined,
252 options.IsGpuProfilingEnabled());
253
254 auto numInputs = getMainModel(model).inputIndexes.size();
255 auto numOutputs = getMainModel(model).outputIndexes.size();
Kevin May42477c12020-03-26 13:34:14 +0000256 try
257 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100258 if (runtime->LoadNetwork(netId, move(optNet), msg, networkProperties) != armnn::Status::Success)
Kevin May42477c12020-03-26 13:34:14 +0000259 {
260 return FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, "Network could not be loaded", cb);
261 }
262 }
263 catch (std::exception& e)
264 {
265 std::stringstream message;
266 message << "Exception (" << e.what()<< ") caught from LoadNetwork.";
267 FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
268 return V1_3::ErrorStatus::NONE;
269 }
270
Sadik Armaganb3021432021-01-13 15:56:51 +0000271 // Now that we have a networkId for the graph rename the exported files to use it
272 // so that we can associate the graph file and the input/output tensor exported files
273 RenameExportedFiles(serializedNetworkFileName,
274 dotGraphFileName,
275 options.GetRequestInputsAndOutputsDumpDir(),
276 netId);
Kevin May42477c12020-03-26 13:34:14 +0000277
278 std::unique_ptr<ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>> preparedModel(
279 new ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>(
280 netId,
281 runtime.get(),
282 model,
283 options.GetRequestInputsAndOutputsDumpDir(),
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100284 options.IsGpuProfilingEnabled(),
Finn Williamsd8fb5402021-05-19 20:52:00 +0100285 priority,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100286 options.isAsyncModelExecutionEnabled(),
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000287 options.getNoOfArmnnThreads(),
288 options.isImportEnabled(),
289 options.isExportEnabled()));
Kevin May42477c12020-03-26 13:34:14 +0000290
291 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
292 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100293 // Only run this if the GpuAcc backend has been added to options
294 if (std::find(options.GetBackends().begin(),
295 options.GetBackends().end(),
296 armnn::Compute::GpuAcc) != options.GetBackends().end())
Kevin May42477c12020-03-26 13:34:14 +0000297 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100298 if (!preparedModel->ExecuteWithDummyInputs(numInputs, numOutputs))
299 {
300 return FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, "Network could not be executed", cb);
301 }
302
303 if (clTunedParameters &&
304 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
305 {
306 // Now that we've done one inference the CL kernel parameters will have been tuned,
307 // so save the updated file.
308 try
309 {
310 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
311 }
312 catch (std::exception& error)
313 {
314 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
315 options.GetClTunedParametersFile().c_str(), error.what());
316 }
317 }
318 }
319 size_t hashValue = 0;
320 // Cache the model
321 if (dataCacheHandle.size() > 0)
322 {
323 // Cache the Arm NN model
324 if (dataCacheHandle.size() != 1)
325 {
326 NotifyCallbackAndCheck(cb, V1_3::ErrorStatus::NONE, preparedModel.release());
327 return V1_3::ErrorStatus::NONE;
328 }
329
330 if (dataCacheHandle[0]->numFds != 1)
331 {
332 ALOGW("ArmnnDriverImpl::prepareArmnnModel_1_3: Cannot cache the data, numFds != 1.");
333 NotifyCallbackAndCheck(cb, V1_3::ErrorStatus::NONE, preparedModel.release());
334 return V1_3::ErrorStatus::NONE;
335 }
Sadik Armaganee6818b2021-11-05 14:41:52 +0000336
337 if (dataCacheHandle[0]->data[0] < 0)
338 {
339 ALOGW("ArmnnDriverImpl::prepareArmnnModel_1_3: Cannot cache the data, fd < 0");
340 NotifyCallbackAndCheck(cb, V1_3::ErrorStatus::NONE, preparedModel.release());
341 return V1_3::ErrorStatus::NONE;
342 }
343
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100344 int dataCacheFileAccessMode = fcntl(dataCacheHandle[0]->data[0], F_GETFL) & O_ACCMODE;
345 if (dataCacheFileAccessMode != O_RDWR)
346 {
347 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3(): Invalid Access Mode.");
348 NotifyCallbackAndCheck(cb, V1_3::ErrorStatus::NONE, preparedModel.release());
349 return V1_3::ErrorStatus::NONE;
350 }
351
352 write(dataCacheHandle[0]->data[0], dataCacheData.data(), dataCacheData.size());
353 hashValue = CacheDataHandlerInstance().Hash(dataCacheData);
Kevin May42477c12020-03-26 13:34:14 +0000354 }
355
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100356 // Cache the model data
357 if (modelCacheHandle.size() > 0)
Kevin May42477c12020-03-26 13:34:14 +0000358 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100359 if (modelCacheHandle.size() != numberOfCachedModelFiles)
Kevin May42477c12020-03-26 13:34:14 +0000360 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100361 NotifyCallbackAndCheck(cb, V1_3::ErrorStatus::NONE, preparedModel.release());
362 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000363 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100364
365 for (uint32_t i = 0; i < modelCacheHandle.size(); ++i)
Kevin May42477c12020-03-26 13:34:14 +0000366 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100367 if (modelCacheHandle[i]->numFds == 1)
368 {
369 int modelCacheFileAccessMode = fcntl(modelCacheHandle[i]->data[0], F_GETFL) & O_ACCMODE;
370 if (modelCacheFileAccessMode != O_RDONLY)
371 {
372 struct stat statBuffer;
373 if (fstat(modelCacheHandle[i]->data[0], &statBuffer) == 0)
374 {
375 long modelDataSize = statBuffer.st_size;
376 if (modelDataSize > 0)
377 {
378 std::vector<uint8_t> modelData(modelDataSize);
379 pread(modelCacheHandle[i]->data[0], modelData.data(), modelData.size(), 0);
380 hashValue ^= CacheDataHandlerInstance().Hash(modelData);
381 }
382 }
383 }
384 }
Kevin May42477c12020-03-26 13:34:14 +0000385 }
386 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100387 if (hashValue != 0)
388 {
389 CacheDataHandlerInstance().Register(token, hashValue, dataCacheData.size());
390 }
Kevin May42477c12020-03-26 13:34:14 +0000391
392 NotifyCallbackAndCheck(cb, V1_3::ErrorStatus::NONE, preparedModel.release());
Ryan OSheac7756cf2022-03-08 01:45:36 +0000393
394 ALOGV("ArmnnDriverImpl::prepareModel cache timing = %lld µs", std::chrono::duration_cast<std::chrono::microseconds>
395 (std::chrono::system_clock::now() - prepareModelTimepoint).count());
396
397
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100398 return V1_3::ErrorStatus::NONE;
399}
Kevin May42477c12020-03-26 13:34:14 +0000400
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100401Return<V1_3::ErrorStatus> ArmnnDriverImpl::prepareModelFromCache_1_3(
402 const armnn::IRuntimePtr& runtime,
403 const DriverOptions& options,
404 const android::hardware::hidl_vec<android::hardware::hidl_handle>& modelCacheHandle,
405 const android::hardware::hidl_vec<android::hardware::hidl_handle>& dataCacheHandle,
406 const HidlToken& token,
407 const android::sp<V1_3::IPreparedModelCallback>& cb)
408{
409 ALOGV("ArmnnDriverImpl::prepareModelFromCache_1_3()");
Ryan OSheac7756cf2022-03-08 01:45:36 +0000410 std::chrono::time_point<std::chrono::system_clock> modelFromCacheTimepoint = std::chrono::system_clock::now();
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100411
412 if (token.size() != ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN)
413 {
414 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
415 return V1_3::ErrorStatus::GENERAL_FAILURE;
416 }
417
418 if (cb.get() == nullptr)
419 {
420 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3: Invalid callback passed to prepareModelFromCache_1_3");
421 return V1_3::ErrorStatus::INVALID_ARGUMENT;
422 }
423
424 if (!runtime)
425 {
426 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3: Device unavailable");
427 return V1_3::ErrorStatus::DEVICE_UNAVAILABLE;
428 }
429
430 // DataCacheHandle size should always be 1
431 // Arm NN model
432 if (dataCacheHandle.size() != 1)
433 {
434 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
435 return V1_3::ErrorStatus::GENERAL_FAILURE;
436 }
437
438 // Check if model files cached they match the expected value
439 unsigned int numberOfCachedModelFiles = 0;
440 for (auto& backend : options.GetBackends())
441 {
442 numberOfCachedModelFiles += GetNumberOfCacheFiles(backend);
443 }
444 if (modelCacheHandle.size() != numberOfCachedModelFiles)
445 {
446 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
447 return V1_3::ErrorStatus::GENERAL_FAILURE;
448 }
449
450 if (dataCacheHandle[0]->numFds != 1)
451 {
452 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3(): Cannot read from the cache data, numFds != 1.");
453 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
454 return V1_3::ErrorStatus::GENERAL_FAILURE;
455 }
456
Sadik Armaganee6818b2021-11-05 14:41:52 +0000457 if (dataCacheHandle[0]->data[0] < 0)
458 {
459 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3(): Cannot read from the cache data, fd < 0");
460 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
461 return V1_3::ErrorStatus::GENERAL_FAILURE;
462 }
463
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100464 int dataCacheFileAccessMode = fcntl(dataCacheHandle[0]->data[0], F_GETFL) & O_ACCMODE;
465 if (dataCacheFileAccessMode != O_RDWR)
466 {
467 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
468 return V1_3::ErrorStatus::GENERAL_FAILURE;
469 }
470
471 auto dataSize = CacheDataHandlerInstance().GetCacheSize(token);
472 if (dataSize == 0)
473 {
474 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3: Invalid data to deserialize!");
475 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
476 return V1_3::ErrorStatus::GENERAL_FAILURE;
477 }
478
479 int offset = 0;
480 {
481 struct stat statBuffer;
482 if (fstat(dataCacheHandle[0]->data[0], &statBuffer) == 0)
483 {
484 unsigned long bufferSize = statBuffer.st_size;
Sadik Armaganee6818b2021-11-05 14:41:52 +0000485 if (bufferSize != dataSize)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100486 {
487 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3: Invalid data to deserialize!");
488 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
489 return V1_3::ErrorStatus::GENERAL_FAILURE;
490 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100491 }
492 }
493 std::vector<uint8_t> dataCacheData(dataSize);
494 pread(dataCacheHandle[0]->data[0], dataCacheData.data(), dataCacheData.size(), offset);
495 auto hashValue = CacheDataHandlerInstance().Hash(dataCacheData);
496
497 int gpuAccCachedFd = -1;
498 bool saveCachedNetwork = false;
499 if (modelCacheHandle.size() > 0)
500 {
501 unsigned int index = 0;
502 for (auto& backend : options.GetBackends())
503 {
504 // modelCacheHandle size should be equal to numberOfCachedModelFiles
505 // modelCacheHandle vector should be in same order as backends
506 auto numberOfCacheFiles = GetNumberOfCacheFiles(backend);
507 if (numberOfCacheFiles > 0)
508 {
509 if (modelCacheHandle[index]->numFds != 1)
510 {
511 ALOGW(
512 "ArmnnDriverImpl::prepareModelFromCache_1_3(): Cannot read from the model cache, numFds != 1.");
513 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
514 return V1_3::ErrorStatus::GENERAL_FAILURE;
515 }
516 auto cachedFd = modelCacheHandle[index]->data[0];
517
518 int modelCacheFileAccessMode = fcntl(cachedFd, F_GETFL) & O_ACCMODE;
519 if (modelCacheFileAccessMode != O_RDWR)
520 {
521 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
522 return V1_3::ErrorStatus::GENERAL_FAILURE;
523 }
524
525 struct stat statBuffer;
526 if (cachedFd != -1 && fstat(cachedFd, &statBuffer) == 0)
527 {
528 long modelDataSize = statBuffer.st_size;
Sadik Armaganee6818b2021-11-05 14:41:52 +0000529 if (modelDataSize <= 0)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100530 {
Sadik Armaganee6818b2021-11-05 14:41:52 +0000531 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3(): Wrong cached model size!");
532 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
533 return V1_3::ErrorStatus::NONE;
534 }
535 std::vector<uint8_t> modelData(modelDataSize);
536 pread(cachedFd, modelData.data(), modelData.size(), 0);
537 hashValue ^= CacheDataHandlerInstance().Hash(modelData);
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100538
Sadik Armaganee6818b2021-11-05 14:41:52 +0000539 // For GpuAcc numberOfCachedFiles is 1
540 if (backend == armnn::Compute::GpuAcc)
541 {
542 gpuAccCachedFd = cachedFd;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100543 }
544 }
545 index += numberOfCacheFiles;
546 }
547 }
548 }
549
Sadik Armaganee6818b2021-11-05 14:41:52 +0000550 if (!CacheDataHandlerInstance().Validate(token, hashValue, dataCacheData.size()))
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100551 {
552 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3: ValidateHash() failed!");
553 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
554 return V1_3::ErrorStatus::GENERAL_FAILURE;
555 }
556
557 // Deserialize the network..
Sadik Armaganee6818b2021-11-05 14:41:52 +0000558 armnn::INetworkPtr network = armnn::INetworkPtr(nullptr, [](armnn::INetwork*){});
559 try
560 {
561 network = armnnDeserializer::IDeserializer::Create()->CreateNetworkFromBinary(dataCacheData);
562 }
563 catch (std::exception&)
564 {
565 ALOGW("ArmnnDriverImpl::prepareModelFromCache_1_3: Exception caught from Deserializer!");
566 cb->notify_1_3(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr);
567 return V1_3::ErrorStatus::GENERAL_FAILURE;
568 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100569
570 // Optimize the network
571 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
John Mcloughlin7c4fc932023-04-07 16:21:49 +0100572 armnn::OptimizerOptionsOpaque OptOptions;
573 OptOptions.SetReduceFp32ToFp16(options.GetFp16Enabled());
574 OptOptions.SetProfilingEnabled(options.IsGpuProfilingEnabled());
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100575
576 armnn::BackendOptions gpuAcc("GpuAcc",
577 {
578 {"FastMathEnabled", options.IsFastMathEnabled()},
579 {"SaveCachedNetwork", saveCachedNetwork},
580 {"CachedNetworkFilePath", options.GetCachedNetworkFilePath()},
581 {"MLGOTuningFilePath", options.GetClMLGOTunedParametersFile()},
582 {"CachedFileDescriptor", gpuAccCachedFd}
583 });
584
585 armnn::BackendOptions cpuAcc("CpuAcc",
586 {
587 {"FastMathEnabled", options.IsFastMathEnabled()},
588 {"NumberOfThreads", options.GetNumberOfThreads()}
589 });
John Mcloughlin7c4fc932023-04-07 16:21:49 +0100590 OptOptions.AddModelOption(gpuAcc);
591 OptOptions.AddModelOption(cpuAcc);
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100592
593 std::vector<std::string> errMessages;
594 try
595 {
596 optNet = armnn::Optimize(*network.get(),
597 options.GetBackends(),
598 runtime->GetDeviceSpec(),
599 OptOptions,
600 errMessages);
601 }
602 catch (std::exception& e)
603 {
604 std::stringstream message;
605 message << "Exception (" << e.what() << ") caught from optimize.";
606 FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
607 return V1_3::ErrorStatus::NONE;
608 }
609
610 // Check that the optimized network is valid.
611 if (!optNet)
612 {
613 std::stringstream message;
614 message << "Invalid optimized network";
615 for (const std::string& msg : errMessages)
616 {
617 message << "\n" << msg;
618 }
619 FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
620 return V1_3::ErrorStatus::NONE;
621 }
622
623 // Export the optimized network graph to a dot file if an output dump directory
624 // has been specified in the drivers' arguments.
625 std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet,
626 options.GetRequestInputsAndOutputsDumpDir());
627
628 // Load it into the runtime.
629 armnn::NetworkId netId = 0;
630 std::string msg;
631 armnn::INetworkProperties networkProperties(options.isAsyncModelExecutionEnabled(),
632 MemorySource::Undefined,
633 MemorySource::Undefined,
634 options.IsGpuProfilingEnabled());
635
636 try
637 {
638 if (runtime->LoadNetwork(netId, move(optNet), msg, networkProperties) != armnn::Status::Success)
639 {
640 return FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, msg, cb);
641 }
642 }
643 catch (std::exception& e)
644 {
645 std::stringstream message;
646 message << "Exception (" << e.what() << ") caught from LoadNetwork.";
647 FailPrepareModel(V1_3::ErrorStatus::GENERAL_FAILURE, message.str(), cb);
648 return V1_3::ErrorStatus::NONE;
649 }
650
651 std::unique_ptr<ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>> preparedModel(
652 new ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>(netId,
653 runtime.get(),
654 options.GetRequestInputsAndOutputsDumpDir(),
655 options.IsGpuProfilingEnabled(),
656 V1_3::Priority::MEDIUM,
657 options.isAsyncModelExecutionEnabled(),
658 options.getNoOfArmnnThreads(),
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000659 options.isImportEnabled(),
660 options.isExportEnabled(),
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100661 true));
662
663 NotifyCallbackAndCheck(cb, V1_3::ErrorStatus::NONE, preparedModel.release());
Ryan OSheac7756cf2022-03-08 01:45:36 +0000664
665 ALOGV("ArmnnDriverImpl::prepareModelFromCache timing = %lld µs",
666 std::chrono::duration_cast<std::chrono::microseconds>
667 (std::chrono::system_clock::now() - modelFromCacheTimepoint).count());
668
Kevin May42477c12020-03-26 13:34:14 +0000669 return V1_3::ErrorStatus::NONE;
670}
671
672Return<void> ArmnnDriverImpl::getCapabilities_1_3(const armnn::IRuntimePtr& runtime,
673 V1_3::IDevice::getCapabilities_1_3_cb cb)
674{
675 ALOGV("hal_1_3::ArmnnDriverImpl::getCapabilities()");
676
677 V1_3::Capabilities capabilities;
678
679 float defaultValue = .1f;
680
681 if (runtime)
682 {
683 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime =
684 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, defaultValue);
685
Kevin May2eaa1192020-04-15 16:50:57 +0100686 capabilities.relaxedFloat32toFloat16PerformanceScalar.powerUsage =
687 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformancePowerUsage, defaultValue);
688
689 capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime =
690 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, defaultValue);
691
Kevin May42477c12020-03-26 13:34:14 +0000692 capabilities.relaxedFloat32toFloat16PerformanceTensor.powerUsage =
693 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformancePowerUsage, defaultValue);
694
Kevin May2eaa1192020-04-15 16:50:57 +0100695 capabilities.ifPerformance.execTime =
696 ParseSystemProperty(g_ifPerformanceExecTime, defaultValue);
697
698 capabilities.ifPerformance.powerUsage =
699 ParseSystemProperty(g_ifPerformancePowerUsage, defaultValue);
700
701 capabilities.whilePerformance.execTime =
702 ParseSystemProperty(g_whilePerformanceExecTime, defaultValue);
703
704 capabilities.whilePerformance.powerUsage =
705 ParseSystemProperty(g_whilePerformancePowerUsage, defaultValue);
706
Kevin May42477c12020-03-26 13:34:14 +0000707 // Set the base value for all operand types
708 capabilities.operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>({FLT_MAX, FLT_MAX});
709
710 // Load supported operand types
711 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32,
712 {
713 .execTime = ParseSystemProperty(g_OperandTypeTensorFloat32PerformanceExecTime, defaultValue),
714 .powerUsage = ParseSystemProperty(g_OperandTypeTensorFloat32PerformancePowerUsage, defaultValue)
715 });
716
717 update(&capabilities.operandPerformance, V1_3::OperandType::FLOAT32,
718 {
719 .execTime = ParseSystemProperty(g_OperandTypeFloat32PerformanceExecTime, defaultValue),
720 .powerUsage = ParseSystemProperty(g_OperandTypeFloat32PerformancePowerUsage, defaultValue)
721 });
722
723 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT16,
724 {
725 .execTime = ParseSystemProperty(g_OperandTypeTensorFloat16PerformanceExecTime, defaultValue),
726 .powerUsage = ParseSystemProperty(g_OperandTypeTensorFloat16PerformancePowerUsage, defaultValue)
727 });
728
729 update(&capabilities.operandPerformance, V1_3::OperandType::FLOAT16,
730 {
731 .execTime = ParseSystemProperty(g_OperandTypeFloat16PerformanceExecTime, defaultValue),
732 .powerUsage = ParseSystemProperty(g_OperandTypeFloat16PerformancePowerUsage, defaultValue)
733 });
734
735 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_ASYMM,
736 {
737 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmPerformanceExecTime, defaultValue),
738 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmPerformancePowerUsage, defaultValue)
739 });
740
741 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_SYMM,
742 {
743 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerformanceExecTime, defaultValue),
744 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerformancePowerUsage, defaultValue)
745 });
746 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED,
747 {
748 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmSignedPerformanceExecTime,
749 defaultValue),
750 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmSignedPerformancePowerUsage,
751 defaultValue)
752 });
753
754 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT16_SYMM,
755 {
756 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant16SymmPerformanceExecTime, defaultValue),
757 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant16SymmPerformancePowerUsage, defaultValue)
758 });
759
760 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL,
761 {
762 .execTime =
763 ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerChannelPerformanceExecTime, defaultValue),
764 .powerUsage =
765 ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerChannelPerformancePowerUsage, defaultValue)
766 });
767
768 update(&capabilities.operandPerformance, V1_3::OperandType::TENSOR_INT32,
769 {
770 .execTime = ParseSystemProperty(g_OperandTypeTensorInt32PerformanceExecTime, defaultValue),
771 .powerUsage = ParseSystemProperty(g_OperandTypeTensorInt32PerformancePowerUsage, defaultValue)
772 });
773
774 update(&capabilities.operandPerformance, V1_3::OperandType::INT32,
775 {
776 .execTime = ParseSystemProperty(g_OperandTypeInt32PerformanceExecTime, defaultValue),
777 .powerUsage = ParseSystemProperty(g_OperandTypeInt32PerformancePowerUsage, defaultValue)
778 });
779
780 cb(V1_3::ErrorStatus::NONE, capabilities);
781 }
782 else
783 {
Kevin May2eaa1192020-04-15 16:50:57 +0100784 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime = 0;
785 capabilities.relaxedFloat32toFloat16PerformanceScalar.powerUsage = 0;
786 capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime = 0;
787 capabilities.relaxedFloat32toFloat16PerformanceTensor.powerUsage = 0;
788 capabilities.ifPerformance.execTime = 0;
789 capabilities.ifPerformance.powerUsage = 0;
790 capabilities.whilePerformance.execTime = 0;
791 capabilities.whilePerformance.powerUsage = 0;
Kevin May42477c12020-03-26 13:34:14 +0000792
793 // Set the base value for all operand types
794 capabilities.operandPerformance = nonExtensionOperandPerformance<HalVersion::V1_3>({0.f, 0.0f});
795
796 cb(V1_3::ErrorStatus::DEVICE_UNAVAILABLE, capabilities);
797 }
798
799 return Void();
800}
801
802} // namespace hal_1_3
803} // namespace armnn_driver