1 //
2 // Copyright © 2020-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include <DelegateOptions.hpp>
7 #include <armnn/utility/NumericCast.hpp>
8 #include <armnn/utility/StringUtils.hpp>
9
10 namespace armnnDelegate
11 {
12
13 struct DelegateOptionsImpl
14 {
15 ~DelegateOptionsImpl() = default;
16 DelegateOptionsImpl() = default;
17
DelegateOptionsImplarmnnDelegate::DelegateOptionsImpl18 explicit DelegateOptionsImpl(armnn::Compute computeDevice,
19 const std::vector<armnn::BackendOptions>& backendOptions,
20 const armnn::Optional<armnn::LogSeverity> logSeverityLevel)
21 : p_Backends({computeDevice}), p_RuntimeOptions(), m_LoggingSeverity(logSeverityLevel)
22 {
23 p_RuntimeOptions.m_BackendOptions = backendOptions;
24 }
25
DelegateOptionsImplarmnnDelegate::DelegateOptionsImpl26 explicit DelegateOptionsImpl(const std::vector<armnn::BackendId>& backends,
27 const std::vector<armnn::BackendOptions>& backendOptions,
28 const armnn::Optional<armnn::LogSeverity> logSeverityLevel)
29 : p_Backends(backends), p_RuntimeOptions(), m_LoggingSeverity(logSeverityLevel)
30 {
31 p_RuntimeOptions.m_BackendOptions = backendOptions;
32 }
33
DelegateOptionsImplarmnnDelegate::DelegateOptionsImpl34 explicit DelegateOptionsImpl(armnn::Compute computeDevice,
35 const armnn::OptimizerOptionsOpaque& optimizerOptions,
36 const armnn::Optional<armnn::LogSeverity>& logSeverityLevel,
37 const armnn::Optional<armnn::DebugCallbackFunction>& func)
38 : p_Backends({computeDevice}),
39 p_RuntimeOptions(),
40 p_OptimizerOptions(optimizerOptions),
41 m_LoggingSeverity(logSeverityLevel),
42 p_DebugCallbackFunc(func)
43 {
44 }
45
DelegateOptionsImplarmnnDelegate::DelegateOptionsImpl46 explicit DelegateOptionsImpl(const std::vector<armnn::BackendId>& backends,
47 const armnn::OptimizerOptionsOpaque& optimizerOptions,
48 const armnn::Optional<armnn::LogSeverity>& logSeverityLevel,
49 const armnn::Optional<armnn::DebugCallbackFunction>& func)
50 : p_Backends(backends),
51 p_RuntimeOptions(),
52 p_OptimizerOptions(optimizerOptions),
53 m_LoggingSeverity(logSeverityLevel),
54 p_DebugCallbackFunc(func)
55 {
56 }
57
58 /// Which backend to run Delegate on.
59 /// Examples of possible values are: CpuRef, CpuAcc, GpuAcc.
60 /// CpuRef as default.
61 std::vector<armnn::BackendId> p_Backends = {armnn::Compute::CpuRef };
62
63 /// Creation options for the ArmNN runtime
64 /// Contains options for global settings that are valid for the whole lifetime of ArmNN
65 /// i.e. BackendOptions, DynamicBackendPath, ExternalProfilingOptions and more
66 armnn::IRuntime::CreationOptions p_RuntimeOptions;
67
68 /// Options for the optimization step for the network
69 armnn::OptimizerOptionsOpaque p_OptimizerOptions;
70
71 /// Internal profiling options. Written to INetworkProperties during model load.
72 /// Indicates whether internal profiling is enabled or not.
73 bool m_InternalProfilingEnabled = false;
74
75 /// Sets the level of detail output by the profiling. Options are DetailsWithEvents = 1 and DetailsOnly = 2
76 armnn::ProfilingDetailsMethod p_InternalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
77
78 /// Severity level for logging within ArmNN that will be used on creation of the delegate
79 armnn::Optional<armnn::LogSeverity> m_LoggingSeverity;
80
81 /// A callback function to debug layers performing custom computations on intermediate tensors.
82 /// If a function is not registered, and debug is enabled in OptimizerOptions,
83 /// debug will print information of the intermediate tensors.
84 armnn::Optional<armnn::DebugCallbackFunction> p_DebugCallbackFunc;
85
86 /// If not empty then the optimized model will be serialized to a file with this file name in "dot" format.
87 std::string m_SerializeToDot = "";
88
89 /// Option to disable TfLite Runtime fallback for unsupported operators.
90 bool m_DisableTfLiteRuntimeFallback = false;
91
92 };
93
94 DelegateOptions::~DelegateOptions() = default;
95
DelegateOptions()96 DelegateOptions::DelegateOptions()
97 : p_DelegateOptionsImpl(std::make_unique<DelegateOptionsImpl>())
98 {
99 }
100
DelegateOptions(DelegateOptions const & other)101 DelegateOptions::DelegateOptions(DelegateOptions const &other)
102 : p_DelegateOptionsImpl(std::make_unique<DelegateOptionsImpl>(*other.p_DelegateOptionsImpl))
103 {
104 }
105
DelegateOptions(armnn::Compute computeDevice,const std::vector<armnn::BackendOptions> & backendOptions,const armnn::Optional<armnn::LogSeverity> logSeverityLevel)106 DelegateOptions::DelegateOptions(armnn::Compute computeDevice,
107 const std::vector<armnn::BackendOptions>& backendOptions,
108 const armnn::Optional<armnn::LogSeverity> logSeverityLevel)
109 : p_DelegateOptionsImpl(std::make_unique<DelegateOptionsImpl>(computeDevice, backendOptions, logSeverityLevel))
110 {
111 }
112
DelegateOptions(const std::vector<armnn::BackendId> & backends,const std::vector<armnn::BackendOptions> & backendOptions,const armnn::Optional<armnn::LogSeverity> logSeverityLevel)113 DelegateOptions::DelegateOptions(const std::vector<armnn::BackendId>& backends,
114 const std::vector<armnn::BackendOptions>& backendOptions,
115 const armnn::Optional<armnn::LogSeverity> logSeverityLevel)
116 : p_DelegateOptionsImpl(std::make_unique<DelegateOptionsImpl>(backends, backendOptions, logSeverityLevel))
117 {
118 }
119
DelegateOptions(armnn::Compute computeDevice,const armnn::OptimizerOptionsOpaque & optimizerOptions,const armnn::Optional<armnn::LogSeverity> & logSeverityLevel,const armnn::Optional<armnn::DebugCallbackFunction> & func)120 DelegateOptions::DelegateOptions(armnn::Compute computeDevice,
121 const armnn::OptimizerOptionsOpaque& optimizerOptions,
122 const armnn::Optional<armnn::LogSeverity>& logSeverityLevel,
123 const armnn::Optional<armnn::DebugCallbackFunction>& func)
124 : p_DelegateOptionsImpl(std::make_unique<DelegateOptionsImpl>(computeDevice, optimizerOptions,
125 logSeverityLevel, func))
126 {
127 }
128
DelegateOptions(const std::vector<armnn::BackendId> & backends,const armnn::OptimizerOptionsOpaque & optimizerOptions,const armnn::Optional<armnn::LogSeverity> & logSeverityLevel,const armnn::Optional<armnn::DebugCallbackFunction> & func)129 DelegateOptions::DelegateOptions(const std::vector<armnn::BackendId>& backends,
130 const armnn::OptimizerOptionsOpaque& optimizerOptions,
131 const armnn::Optional<armnn::LogSeverity>& logSeverityLevel,
132 const armnn::Optional<armnn::DebugCallbackFunction>& func)
133 : p_DelegateOptionsImpl(std::make_unique<DelegateOptionsImpl>(backends, optimizerOptions,
134 logSeverityLevel, func))
135 {
136 }
137
DelegateOptions(char const * const * options_keys,char const * const * options_values,size_t num_options,void (* report_error)(const char *))138 DelegateOptions::DelegateOptions(char const* const* options_keys,
139 char const* const* options_values,
140 size_t num_options,
141 void (*report_error)(const char*))
142 : p_DelegateOptionsImpl(std::make_unique<DelegateOptionsImpl>())
143 {
144 armnn::IRuntime::CreationOptions runtimeOptions;
145 armnn::OptimizerOptionsOpaque optimizerOptions;
146 bool internalProfilingState = false;
147 armnn::ProfilingDetailsMethod internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
148 for (size_t i = 0; i < num_options; ++i)
149 {
150 // Process backends
151 if (std::string(options_keys[i]) == std::string("backends"))
152 {
153 // The backend option is a comma separated string of backendIDs that needs to be split
154 std::vector<armnn::BackendId> backends;
155 char* dup = strdup(options_values[i]);
156 char* pch = std::strtok(dup, ",");
157 while (pch != NULL)
158 {
159 backends.push_back(pch);
160 pch = strtok (NULL, ",");
161 }
162 SetBackends(backends);
163 }
164 // Process dynamic-backends-path
165 else if (std::string(options_keys[i]) == std::string("dynamic-backends-path"))
166 {
167 runtimeOptions.m_DynamicBackendsPath = std::string(options_values[i]);
168 }
169 // Process logging level
170 else if (std::string(options_keys[i]) == std::string("logging-severity"))
171 {
172 SetLoggingSeverity(options_values[i]);
173 }
174 // Process GPU backend options
175 else if (std::string(options_keys[i]) == std::string("gpu-tuning-level"))
176 {
177 armnn::BackendOptions option("GpuAcc", {{"TuningLevel",
178 atoi(options_values[i])}});
179 runtimeOptions.m_BackendOptions.push_back(option);
180 }
181 else if (std::string(options_keys[i]) == std::string("gpu-mlgo-tuning-file"))
182 {
183 armnn::BackendOptions option("GpuAcc", {{"MLGOTuningFilePath",
184 std::string(options_values[i])}});
185 optimizerOptions.AddModelOption(option);
186 }
187 else if (std::string(options_keys[i]) == std::string("gpu-tuning-file"))
188 {
189 armnn::BackendOptions option("GpuAcc", {{"TuningFile",
190 std::string(options_values[i])}});
191 runtimeOptions.m_BackendOptions.push_back(option);
192 }
193 else if (std::string(options_keys[i]) == std::string("gpu-enable-profiling"))
194 {
195 runtimeOptions.m_EnableGpuProfiling = (*options_values[i] != '0');
196 }
197 else if (std::string(options_keys[i]) == std::string("gpu-kernel-profiling-enabled"))
198 {
199 armnn::BackendOptions option("GpuAcc", {{"KernelProfilingEnabled",
200 armnn::stringUtils::StringToBool(options_values[i])}});
201 runtimeOptions.m_BackendOptions.push_back(option);
202 }
203 else if (std::string(options_keys[i]) == std::string("save-cached-network"))
204 {
205 armnn::BackendOptions option("GpuAcc", {{"SaveCachedNetwork",
206 armnn::stringUtils::StringToBool(options_values[i])}});
207 optimizerOptions.AddModelOption(option);
208 }
209 else if (std::string(options_keys[i]) == std::string("cached-network-filepath"))
210 {
211 armnn::BackendOptions option("GpuAcc", {{"CachedNetworkFilePath",
212 std::string(options_values[i])}});
213 optimizerOptions.AddModelOption(option);
214 }
215 // Process GPU & CPU backend options
216 else if (std::string(options_keys[i]) == std::string("enable-fast-math"))
217 {
218 armnn::BackendOptions modelOptionGpu("GpuAcc", {{"FastMathEnabled",
219 armnn::stringUtils::StringToBool(options_values[i])}});
220 optimizerOptions.AddModelOption(modelOptionGpu);
221
222 armnn::BackendOptions modelOptionCpu("CpuAcc", {{"FastMathEnabled",
223 armnn::stringUtils::StringToBool(options_values[i])}});
224 optimizerOptions.AddModelOption(modelOptionCpu);
225 }
226 // Process CPU backend options
227 else if (std::string(options_keys[i]) == std::string("number-of-threads"))
228 {
229 unsigned int numberOfThreads = armnn::numeric_cast<unsigned int>(atoi(options_values[i]));
230 armnn::BackendOptions modelOption("CpuAcc",
231 {{"NumberOfThreads", numberOfThreads}});
232 optimizerOptions.AddModelOption(modelOption);
233 }
234 // Process reduce-fp32-to-fp16 option
235 else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-fp16"))
236 {
237 optimizerOptions.SetReduceFp32ToFp16(armnn::stringUtils::StringToBool(options_values[i]));
238 }
239 // Process debug-data
240 else if (std::string(options_keys[i]) == std::string("debug-data"))
241 {
242 optimizerOptions.SetDebugEnabled(armnn::stringUtils::StringToBool(options_values[i]));
243 }
244 // Infer output-shape
245 else if (std::string(options_keys[i]) == std::string("infer-output-shape"))
246 {
247 armnn::BackendOptions backendOption("ShapeInferenceMethod",
248 {
249 { "InferAndValidate", armnn::stringUtils::StringToBool(options_values[i]) }
250 });
251 optimizerOptions.AddModelOption(backendOption);
252 }
253 // Allow expanded dims
254 else if (std::string(options_keys[i]) == std::string("allow-expanded-dims"))
255 {
256 armnn::BackendOptions backendOption("AllowExpandedDims",
257 {
258 { "AllowExpandedDims", armnn::stringUtils::StringToBool(options_values[i]) }
259 });
260 optimizerOptions.AddModelOption(backendOption);
261 }
262 // Process memory-import
263 else if (std::string(options_keys[i]) == std::string("memory-import"))
264 {
265 optimizerOptions.SetImportEnabled(armnn::stringUtils::StringToBool(options_values[i]));
266 }
267 // Process enable-internal-profiling
268 else if (std::string(options_keys[i]) == std::string("enable-internal-profiling"))
269 {
270 internalProfilingState = *options_values[i] != '0';
271 optimizerOptions.SetProfilingEnabled(internalProfilingState);
272 }
273 // Process internal-profiling-detail
274 else if (std::string(options_keys[i]) == std::string("internal-profiling-detail"))
275 {
276 uint32_t detailLevel = static_cast<uint32_t>(std::stoul(options_values[i]));
277 switch (detailLevel)
278 {
279 case 1:
280 internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
281 break;
282 case 2:
283 internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsOnly;
284 break;
285 default:
286 internalProfilingDetail = armnn::ProfilingDetailsMethod::Undefined;
287 break;
288 }
289 }
290 // Process enable-external-profiling
291 else if (std::string(options_keys[i]) == std::string("enable-external-profiling"))
292 {
293 runtimeOptions.m_ProfilingOptions.m_EnableProfiling =
294 armnn::stringUtils::StringToBool(options_values[i]);
295 }
296 // Process timeline-profiling
297 else if (std::string(options_keys[i]) == std::string("timeline-profiling"))
298 {
299 runtimeOptions.m_ProfilingOptions.m_TimelineEnabled =
300 armnn::stringUtils::StringToBool(options_values[i]);
301 }
302 // Process outgoing-capture-file
303 else if (std::string(options_keys[i]) == std::string("outgoing-capture-file"))
304 {
305 runtimeOptions.m_ProfilingOptions.m_OutgoingCaptureFile = options_values[i];
306 }
307 // Process incoming-capture-file
308 else if (std::string(options_keys[i]) == std::string("incoming-capture-file"))
309 {
310 runtimeOptions.m_ProfilingOptions.m_IncomingCaptureFile = options_values[i];
311 }
312 // Process file-only-external-profiling
313 else if (std::string(options_keys[i]) == std::string("file-only-external-profiling"))
314 {
315 runtimeOptions.m_ProfilingOptions.m_FileOnly =
316 armnn::stringUtils::StringToBool(options_values[i]);
317 }
318 // Process counter-capture-period
319 else if (std::string(options_keys[i]) == std::string("counter-capture-period"))
320 {
321 runtimeOptions.m_ProfilingOptions.m_CapturePeriod =
322 static_cast<uint32_t>(std::stoul(options_values[i]));
323 }
324 // Process profiling-file-format
325 else if (std::string(options_keys[i]) == std::string("profiling-file-format"))
326 {
327 runtimeOptions.m_ProfilingOptions.m_FileFormat = options_values[i];
328 }
329 // Process serialize-to-dot
330 else if (std::string(options_keys[i]) == std::string("serialize-to-dot"))
331 {
332 SetSerializeToDot(options_values[i]);
333 }
334
335 // Process disable-tflite-runtime-fallback
336 else if (std::string(options_keys[i]) == std::string("disable-tflite-runtime-fallback"))
337 {
338 this->DisableTfLiteRuntimeFallback(armnn::stringUtils::StringToBool(options_values[i]));
339 }
340 else
341 {
342 throw armnn::Exception("Unknown option for the ArmNN Delegate given: " +
343 std::string(options_keys[i]));
344 }
345 }
346
347 SetRuntimeOptions(runtimeOptions);
348 SetOptimizerOptions(optimizerOptions);
349 SetInternalProfilingParams(internalProfilingState, internalProfilingDetail);
350 }
351
GetBackends() const352 const std::vector<armnn::BackendId>& DelegateOptions::GetBackends() const
353 {
354 return p_DelegateOptionsImpl->p_Backends;
355 }
356
SetBackends(const std::vector<armnn::BackendId> & backends)357 void DelegateOptions::SetBackends(const std::vector<armnn::BackendId>& backends)
358 {
359 p_DelegateOptionsImpl->p_Backends = backends;
360 }
361
SetDynamicBackendsPath(const std::string & dynamicBackendsPath)362 void DelegateOptions::SetDynamicBackendsPath(const std::string& dynamicBackendsPath)
363 {
364 p_DelegateOptionsImpl->p_RuntimeOptions.m_DynamicBackendsPath = dynamicBackendsPath;
365 }
366
GetDynamicBackendsPath() const367 const std::string& DelegateOptions::GetDynamicBackendsPath() const
368 {
369 return p_DelegateOptionsImpl->p_RuntimeOptions.m_DynamicBackendsPath;
370 }
371
SetGpuProfilingState(bool gpuProfilingState)372 void DelegateOptions::SetGpuProfilingState(bool gpuProfilingState)
373 {
374 p_DelegateOptionsImpl->p_RuntimeOptions.m_EnableGpuProfiling = gpuProfilingState;
375 }
376
GetGpuProfilingState()377 bool DelegateOptions::GetGpuProfilingState()
378 {
379 return p_DelegateOptionsImpl->p_RuntimeOptions.m_EnableGpuProfiling;
380 }
381
GetBackendOptions() const382 const std::vector<armnn::BackendOptions>& DelegateOptions::GetBackendOptions() const
383 {
384 return p_DelegateOptionsImpl->p_RuntimeOptions.m_BackendOptions;
385 }
386
AddBackendOption(const armnn::BackendOptions & option)387 void DelegateOptions::AddBackendOption(const armnn::BackendOptions& option)
388 {
389 p_DelegateOptionsImpl->p_RuntimeOptions.m_BackendOptions.push_back(option);
390 }
391
SetLoggingSeverity(const armnn::LogSeverity & level)392 void DelegateOptions::SetLoggingSeverity(const armnn::LogSeverity& level)
393 {
394 p_DelegateOptionsImpl->m_LoggingSeverity = level;
395 }
396
SetLoggingSeverity(const std::string & level)397 void DelegateOptions::SetLoggingSeverity(const std::string& level)
398 {
399 p_DelegateOptionsImpl->m_LoggingSeverity = armnn::StringToLogLevel(level);
400 }
401
GetLoggingSeverity()402 armnn::LogSeverity DelegateOptions::GetLoggingSeverity()
403 {
404 return p_DelegateOptionsImpl->m_LoggingSeverity.value();
405 }
406
IsLoggingEnabled()407 bool DelegateOptions::IsLoggingEnabled()
408 {
409 return p_DelegateOptionsImpl->m_LoggingSeverity.has_value();
410 }
411
GetOptimizerOptions() const412 const armnn::OptimizerOptionsOpaque& DelegateOptions::GetOptimizerOptions() const
413 {
414 return p_DelegateOptionsImpl->p_OptimizerOptions;
415 }
416
SetOptimizerOptions(const armnn::OptimizerOptionsOpaque & optimizerOptions)417 void DelegateOptions::SetOptimizerOptions(const armnn::OptimizerOptionsOpaque& optimizerOptions)
418 {
419 p_DelegateOptionsImpl->p_OptimizerOptions = optimizerOptions;
420 }
421
GetDebugCallbackFunction() const422 const armnn::Optional<armnn::DebugCallbackFunction>& DelegateOptions::GetDebugCallbackFunction() const
423 {
424 return p_DelegateOptionsImpl->p_DebugCallbackFunc;
425 }
426
SetInternalProfilingParams(bool internalProfilingState,const armnn::ProfilingDetailsMethod & internalProfilingDetail)427 void DelegateOptions::SetInternalProfilingParams(bool internalProfilingState,
428 const armnn::ProfilingDetailsMethod& internalProfilingDetail)
429 {
430 p_DelegateOptionsImpl->m_InternalProfilingEnabled = internalProfilingState;
431 p_DelegateOptionsImpl->p_InternalProfilingDetail = internalProfilingDetail;
432 }
433
GetInternalProfilingState() const434 bool DelegateOptions::GetInternalProfilingState() const
435 {
436 return p_DelegateOptionsImpl->m_InternalProfilingEnabled;
437 }
438
GetInternalProfilingDetail() const439 const armnn::ProfilingDetailsMethod& DelegateOptions::GetInternalProfilingDetail() const
440 {
441 return p_DelegateOptionsImpl->p_InternalProfilingDetail;
442 }
443
SetSerializeToDot(const std::string & serializeToDotFile)444 void DelegateOptions::SetSerializeToDot(const std::string& serializeToDotFile)
445 {
446 p_DelegateOptionsImpl->m_SerializeToDot = serializeToDotFile;
447 }
448
GetSerializeToDot() const449 const std::string& DelegateOptions::GetSerializeToDot() const
450 {
451 return p_DelegateOptionsImpl->m_SerializeToDot;
452 }
453
SetRuntimeOptions(const armnn::IRuntime::CreationOptions & runtimeOptions)454 void DelegateOptions::SetRuntimeOptions(const armnn::IRuntime::CreationOptions& runtimeOptions)
455 {
456 p_DelegateOptionsImpl->p_RuntimeOptions = runtimeOptions;
457 }
458
GetRuntimeOptions()459 const armnn::IRuntime::CreationOptions& DelegateOptions::GetRuntimeOptions()
460 {
461 return p_DelegateOptionsImpl->p_RuntimeOptions;
462 }
463
DisableTfLiteRuntimeFallback(bool fallbackState)464 void DelegateOptions::DisableTfLiteRuntimeFallback(bool fallbackState)
465 {
466 p_DelegateOptionsImpl->m_DisableTfLiteRuntimeFallback = fallbackState;
467 }
468
TfLiteRuntimeFallbackDisabled()469 bool DelegateOptions::TfLiteRuntimeFallbackDisabled()
470 {
471 return p_DelegateOptionsImpl->m_DisableTfLiteRuntimeFallback;
472 }
473
474 } // namespace armnnDelegate
475