blob: 1abe0f394bd42cf3b190ca1e647582f7146d59fb [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
Jim Flynn6398a982020-05-27 17:05:21 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5#include "Runtime.hpp"
6
David Beck056be3c2018-10-22 13:16:00 +01007#include <armnn/Version.hpp>
Matteo Martincighc601aa62019-10-29 15:03:22 +00008#include <armnn/BackendRegistry.hpp>
Jan Eilers15fcc7e2021-07-14 13:50:15 +01009#include <armnn/BackendHelper.hpp>
Matthew Benthamf48afc62020-01-15 17:55:08 +000010#include <armnn/Logging.hpp>
alered01a7227ac2020-05-07 14:58:29 +010011#include <armnn/utility/Timer.hpp>
Matteo Martincighe54aa062019-08-05 14:12:11 +010012
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000013#include <armnn/backends/IBackendContext.hpp>
Matteo Martincighe54aa062019-08-05 14:12:11 +010014#include <backendsCommon/DynamicBackendUtils.hpp>
Jim Flynne1fdd282021-10-26 21:26:10 +010015#include <backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyLibrary.hpp>
Jan Eilersbb446e52020-04-02 13:56:54 +010016#include <armnn/utility/PolymorphicDowncast.hpp>
telsoa014fcda012018-03-09 14:13:49 +000017
Nikhil Raj77fe76b2021-06-09 14:55:32 +010018#include <common/include/LabelsAndEventClasses.hpp>
19
surmeh013537c2c2018-05-18 16:31:43 +010020#include <iostream>
21
Colm Donelan1aff3932020-02-05 17:48:59 +000022#include <backends/BackendProfiling.hpp>
telsoa014fcda012018-03-09 14:13:49 +000023
24using namespace armnn;
25using namespace std;
26
27namespace armnn
28{
Kevin Mayd92a6e42021-02-04 10:27:41 +000029IRuntime::IRuntime() : pRuntimeImpl( new RuntimeImpl(armnn::IRuntime::CreationOptions())) {}
30
31IRuntime::IRuntime(const IRuntime::CreationOptions& options) : pRuntimeImpl(new RuntimeImpl(options)) {}
32
33IRuntime::~IRuntime() = default;
telsoa014fcda012018-03-09 14:13:49 +000034
35IRuntime* IRuntime::CreateRaw(const CreationOptions& options)
36{
Kevin Mayd92a6e42021-02-04 10:27:41 +000037 return new IRuntime(options);
telsoa014fcda012018-03-09 14:13:49 +000038}
39
40IRuntimePtr IRuntime::Create(const CreationOptions& options)
41{
42 return IRuntimePtr(CreateRaw(options), &IRuntime::Destroy);
43}
44
45void IRuntime::Destroy(IRuntime* runtime)
46{
Kevin Mayd92a6e42021-02-04 10:27:41 +000047 delete runtime;
telsoa014fcda012018-03-09 14:13:49 +000048}
49
Kevin Mayd92a6e42021-02-04 10:27:41 +000050Status IRuntime::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr network)
51{
52 return pRuntimeImpl->LoadNetwork(networkIdOut, std::move(network));
53}
54
55Status IRuntime::LoadNetwork(NetworkId& networkIdOut,
56 IOptimizedNetworkPtr network,
57 std::string& errorMessage)
58{
59 return pRuntimeImpl->LoadNetwork(networkIdOut, std::move(network), errorMessage);
60}
61
62Status IRuntime::LoadNetwork(NetworkId& networkIdOut,
63 IOptimizedNetworkPtr network,
64 std::string& errorMessage,
65 const INetworkProperties& networkProperties)
66{
67 return pRuntimeImpl->LoadNetwork(networkIdOut, std::move(network), errorMessage, networkProperties);
68}
69
Cathal Corbett5b8093c2021-10-22 11:12:07 +010070armnn::TensorInfo IRuntime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
Kevin Mayd92a6e42021-02-04 10:27:41 +000071{
72 return pRuntimeImpl->GetInputTensorInfo(networkId, layerId);
73}
74
Cathal Corbett5b8093c2021-10-22 11:12:07 +010075armnn::TensorInfo IRuntime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
Kevin Mayd92a6e42021-02-04 10:27:41 +000076{
77 return pRuntimeImpl->GetOutputTensorInfo(networkId, layerId);
78}
79
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +000080std::vector<ImportedInputId> IRuntime::ImportInputs(NetworkId networkId, const InputTensors& inputTensors,
81 MemorySource forceImportMemorySource)
Finn Williamsf37b9702021-09-01 18:06:04 +010082{
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +000083 return pRuntimeImpl->ImportInputs(networkId, inputTensors, forceImportMemorySource);
Finn Williamsf37b9702021-09-01 18:06:04 +010084}
85
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +000086std::vector<ImportedOutputId> IRuntime::ImportOutputs(NetworkId networkId, const OutputTensors& outputTensors,
87 MemorySource forceImportMemorySource)
Finn Williams8636bc72021-10-02 15:06:39 +010088{
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +000089 return pRuntimeImpl->ImportOutputs(networkId, outputTensors, forceImportMemorySource);
Finn Williams8636bc72021-10-02 15:06:39 +010090}
91
92void IRuntime::ClearImportedInputs(NetworkId networkId, const std::vector<ImportedInputId> inputIds)
93{
94 return pRuntimeImpl->ClearImportedInputs(networkId, inputIds);
95}
96void IRuntime::ClearImportedOutputs(NetworkId networkId, const std::vector<ImportedOutputId> outputIds)
97{
98 return pRuntimeImpl->ClearImportedOutputs(networkId, outputIds);
99}
Finn Williamsf37b9702021-09-01 18:06:04 +0100100
Kevin Mayd92a6e42021-02-04 10:27:41 +0000101Status IRuntime::EnqueueWorkload(NetworkId networkId,
102 const InputTensors& inputTensors,
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000103 const OutputTensors& outputTensors,
104 std::vector<ImportedInputId> preImportedInputIds,
105 std::vector<ImportedOutputId> preImportedOutputIds)
Kevin Mayd92a6e42021-02-04 10:27:41 +0000106{
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000107 return pRuntimeImpl->EnqueueWorkload(networkId, inputTensors, outputTensors,
108 preImportedInputIds, preImportedOutputIds);
Kevin Mayd92a6e42021-02-04 10:27:41 +0000109}
110
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100111Status IRuntime::Execute(IWorkingMemHandle& workingMemHandle,
112 const InputTensors& inputTensors,
Finn Williamsf37b9702021-09-01 18:06:04 +0100113 const OutputTensors& outputTensors,
Finn Williams8636bc72021-10-02 15:06:39 +0100114 std::vector<ImportedInputId> preImportedInputs,
115 std::vector<ImportedOutputId> preImportedOutputs)
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100116{
Finn Williams8636bc72021-10-02 15:06:39 +0100117 return pRuntimeImpl->Execute(workingMemHandle, inputTensors, outputTensors, preImportedInputs, preImportedOutputs);
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100118}
119
Kevin Mayd92a6e42021-02-04 10:27:41 +0000120Status IRuntime::UnloadNetwork(NetworkId networkId)
121{
122 return pRuntimeImpl->UnloadNetwork(networkId);
123}
124
125const IDeviceSpec& IRuntime::GetDeviceSpec() const
126{
127 return pRuntimeImpl->GetDeviceSpec();
128}
129
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100130std::unique_ptr<IWorkingMemHandle> IRuntime::CreateWorkingMemHandle(NetworkId networkId)
131{
132 return pRuntimeImpl->CreateWorkingMemHandle(networkId);
133}
134
Kevin Mayd92a6e42021-02-04 10:27:41 +0000135const std::shared_ptr<IProfiler> IRuntime::GetProfiler(NetworkId networkId) const
136{
137 return pRuntimeImpl->GetProfiler(networkId);
138}
139
140void IRuntime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
141{
142 return pRuntimeImpl->RegisterDebugCallback(networkId, func);
143}
144
145int RuntimeImpl::GenerateNetworkId()
telsoa014fcda012018-03-09 14:13:49 +0000146{
147 return m_NetworkIdCounter++;
148}
149
Kevin Mayd92a6e42021-02-04 10:27:41 +0000150Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr inNetwork)
telsoa014fcda012018-03-09 14:13:49 +0000151{
telsoa01c577f2c2018-08-31 09:22:23 +0100152 std::string ignoredErrorMessage;
153 return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
154}
155
Kevin Mayd92a6e42021-02-04 10:27:41 +0000156Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut,
157 IOptimizedNetworkPtr inNetwork,
158 std::string& errorMessage)
David Monahan4f1e8e42019-09-04 09:22:10 +0100159{
Jan Eilersc1c872f2021-07-22 13:17:04 +0100160 INetworkProperties networkProperties(
161 false, MemorySource::Undefined, MemorySource::Undefined);
David Monahan4f1e8e42019-09-04 09:22:10 +0100162 return LoadNetwork(networkIdOut, std::move(inNetwork), errorMessage, networkProperties);
163}
164
Kevin Mayd92a6e42021-02-04 10:27:41 +0000165Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut,
166 IOptimizedNetworkPtr inNetwork,
167 std::string& errorMessage,
168 const INetworkProperties& networkProperties)
telsoa01c577f2c2018-08-31 09:22:23 +0100169{
Derek Lambertie155bbf2021-10-13 14:32:12 +0100170 // Register the profiler
171 auto profiler = inNetwork->GetProfiler();
172 ProfilerManager::GetInstance().RegisterProfiler(profiler.get());
173
telsoa014fcda012018-03-09 14:13:49 +0000174 IOptimizedNetwork* rawNetwork = inNetwork.release();
David Beck1b61be52018-11-08 09:19:14 +0000175
176 networkIdOut = GenerateNetworkId();
177
178 for (auto&& context : m_BackendContexts)
179 {
180 context.second->BeforeLoadNetwork(networkIdOut);
181 }
182
telsoa014fcda012018-03-09 14:13:49 +0000183 unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000184 std::unique_ptr<IOptimizedNetwork>(rawNetwork),
David Monahan4f1e8e42019-09-04 09:22:10 +0100185 errorMessage,
Sadik Armagan3184c902020-03-18 10:57:30 +0000186 networkProperties,
Finn Williamsf364d532021-06-09 17:07:33 +0100187 m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +0000188
189 if (!loadedNetwork)
190 {
191 return Status::Failure;
192 }
193
telsoa01c577f2c2018-08-31 09:22:23 +0100194 {
195 std::lock_guard<std::mutex> lockGuard(m_Mutex);
196
197 // Stores the network
198 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
199 }
telsoa014fcda012018-03-09 14:13:49 +0000200
David Beck1b61be52018-11-08 09:19:14 +0000201 for (auto&& context : m_BackendContexts)
202 {
203 context.second->AfterLoadNetwork(networkIdOut);
204 }
205
Sadik Armagan3184c902020-03-18 10:57:30 +0000206 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000207 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000208 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_LOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000209 }
210
telsoa014fcda012018-03-09 14:13:49 +0000211 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +0000212}
213
Kevin Mayd92a6e42021-02-04 10:27:41 +0000214Status RuntimeImpl::UnloadNetwork(NetworkId networkId)
telsoa014fcda012018-03-09 14:13:49 +0000215{
David Beck1b61be52018-11-08 09:19:14 +0000216 bool unloadOk = true;
217 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +0000218 {
David Beck1b61be52018-11-08 09:19:14 +0000219 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +0000220 }
David Beck1b61be52018-11-08 09:19:14 +0000221
222 if (!unloadOk)
223 {
Kevin Mayd92a6e42021-02-04 10:27:41 +0000224 ARMNN_LOG(warning) << "RuntimeImpl::UnloadNetwork(): failed to unload "
Derek Lamberti08446972019-11-26 16:38:31 +0000225 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
David Beck1b61be52018-11-08 09:19:14 +0000226 return Status::Failure;
227 }
David Beck9efb57d2018-11-05 13:40:33 +0000228
Jim Flynnf7713212020-07-14 09:50:59 +0100229 std::unique_ptr<profiling::TimelineUtilityMethods> timelineUtils =
230 profiling::TimelineUtilityMethods::GetTimelineUtils(m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +0000231 {
telsoa01c577f2c2018-08-31 09:22:23 +0100232 std::lock_guard<std::mutex> lockGuard(m_Mutex);
233
Jim Flynnf7713212020-07-14 09:50:59 +0100234 // If timeline recording is on mark the Network end of life
235 if (timelineUtils)
236 {
237 auto search = m_LoadedNetworks.find(networkId);
238 if (search != m_LoadedNetworks.end())
239 {
240 profiling::ProfilingGuid networkGuid = search->second->GetNetworkGuid();
241 timelineUtils->RecordEvent(networkGuid,
242 profiling::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
243 }
244 }
Narumol Prangnawaratec5463d2022-02-04 17:50:20 +0000245
telsoa01c577f2c2018-08-31 09:22:23 +0100246 if (m_LoadedNetworks.erase(networkId) == 0)
247 {
Kevin Mayd92a6e42021-02-04 10:27:41 +0000248 ARMNN_LOG(warning) << "WARNING: RuntimeImpl::UnloadNetwork(): " << networkId << " not found!";
telsoa01c577f2c2018-08-31 09:22:23 +0100249 return Status::Failure;
250 }
Sadik Armagan3184c902020-03-18 10:57:30 +0000251
252 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000253 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000254 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_UNLOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000255 }
David Beck1b61be52018-11-08 09:19:14 +0000256 }
David Beck9efb57d2018-11-05 13:40:33 +0000257
David Beck1b61be52018-11-08 09:19:14 +0000258 for (auto&& context : m_BackendContexts)
259 {
260 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100261 }
262
Derek Lambertie155bbf2021-10-13 14:32:12 +0100263 // Unregister the profiler
264 ProfilerManager::GetInstance().RegisterProfiler(nullptr);
265
Kevin Mayd92a6e42021-02-04 10:27:41 +0000266 ARMNN_LOG(debug) << "RuntimeImpl::UnloadNetwork(): Unloaded network with ID: " << networkId;
telsoa014fcda012018-03-09 14:13:49 +0000267 return Status::Success;
268}
269
Kevin Mayd92a6e42021-02-04 10:27:41 +0000270const std::shared_ptr<IProfiler> RuntimeImpl::GetProfiler(NetworkId networkId) const
telsoa01c577f2c2018-08-31 09:22:23 +0100271{
272 auto it = m_LoadedNetworks.find(networkId);
273 if (it != m_LoadedNetworks.end())
274 {
275 auto& loadedNetwork = it->second;
276 return loadedNetwork->GetProfiler();
277 }
278
279 return nullptr;
280}
281
Kevin Mayd92a6e42021-02-04 10:27:41 +0000282void RuntimeImpl::ReportStructure() // armnn::profiling::IProfilingService& profilingService as param
Keith Davis33ed2212020-03-30 10:43:41 +0100283{
284 // No-op for the time being, but this may be useful in future to have the profilingService available
285 // if (profilingService.IsProfilingEnabled()){}
286
287 LoadedNetworks::iterator it = m_LoadedNetworks.begin();
288 while (it != m_LoadedNetworks.end())
289 {
290 auto& loadedNetwork = it->second;
291 loadedNetwork->SendNetworkStructure();
292 // Increment the Iterator to point to next entry
293 it++;
294 }
295}
296
Kevin Mayd92a6e42021-02-04 10:27:41 +0000297RuntimeImpl::RuntimeImpl(const IRuntime::CreationOptions& options)
Keith Davis33ed2212020-03-30 10:43:41 +0100298 : m_NetworkIdCounter(0),
299 m_ProfilingService(*this)
telsoa014fcda012018-03-09 14:13:49 +0000300{
alered01a7227ac2020-05-07 14:58:29 +0100301 const auto start_time = armnn::GetTimeNow();
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000302 ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION;
Keith Davis33ed2212020-03-30 10:43:41 +0100303 if ( options.m_ProfilingOptions.m_TimelineEnabled && !options.m_ProfilingOptions.m_EnableProfiling )
304 {
Jan Eilersc1c872f2021-07-22 13:17:04 +0100305 throw RuntimeException(
306 "It is not possible to enable timeline reporting without profiling being enabled");
Keith Davis33ed2212020-03-30 10:43:41 +0100307 }
308
Matteo Martincighe54aa062019-08-05 14:12:11 +0100309 // Load any available/compatible dynamic backend before the runtime
310 // goes through the backend registry
311 LoadDynamicBackends(options.m_DynamicBackendsPath);
312
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000313 BackendIdSet supportedBackends;
David Beck1b61be52018-11-08 09:19:14 +0000314 for (const auto& id : BackendRegistryInstance().GetBackendIds())
315 {
316 // Store backend contexts for the supported ones
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000317 try {
David Beck1b61be52018-11-08 09:19:14 +0000318 auto factoryFun = BackendRegistryInstance().GetFactory(id);
Colm Donelan380c1a02021-08-17 00:52:23 +0100319 ARMNN_ASSERT(factoryFun != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000320 auto backend = factoryFun();
Colm Donelan380c1a02021-08-17 00:52:23 +0100321 ARMNN_ASSERT(backend != nullptr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100322 ARMNN_ASSERT(backend.get() != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000323
Jan Eilersc1c872f2021-07-22 13:17:04 +0100324 auto customAllocatorMapIterator = options.m_CustomAllocatorMap.find(id);
Francis Murtagh62573b62021-08-12 11:55:21 +0100325 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end() &&
326 customAllocatorMapIterator->second == nullptr)
327 {
Colm Donelan380c1a02021-08-17 00:52:23 +0100328 // We need to manually clean up the dynamic backends before throwing an exception.
329 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
330 m_DeviceSpec.ClearDynamicBackends();
Francis Murtagh62573b62021-08-12 11:55:21 +0100331 throw armnn::Exception("Allocator associated with id " + id.Get() + " is null");
332 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100333
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100334 // If the runtime is created in protected mode only add backends that support this mode
335 if (options.m_ProtectedMode)
336 {
337 // check if backend supports ProtectedMode
338 using BackendCapability = BackendOptions::BackendOption;
339 BackendCapability protectedContentCapability {"ProtectedContentAllocation", true};
340 if (!HasCapability(protectedContentCapability, id))
341 {
342 // Protected Content Allocation is not supported by the backend
343 // backend should not be registered
344 ARMNN_LOG(warning) << "Backend "
345 << id
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000346 << " is not registered as does not support protected content allocation.";
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100347 continue;
348 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100349 // The user is responsible to provide a custom memory allocator which allows to allocate
350 // protected memory
351 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end())
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100352 {
Jan Eilersc1c872f2021-07-22 13:17:04 +0100353 std::string err;
354 if (customAllocatorMapIterator->second->GetMemorySourceType()
355 == armnn::MemorySource::DmaBufProtected)
356 {
357 if (!backend->UseCustomMemoryAllocator(customAllocatorMapIterator->second, err))
358 {
359 ARMNN_LOG(error) << "The backend "
360 << id
361 << " reported an error when entering protected mode. Backend won't be"
362 << " used. ErrorMsg: " << err;
363 continue;
364 }
365 // No errors so register the Custom Allocator with the BackendRegistry
366 BackendRegistryInstance().RegisterAllocator(id, customAllocatorMapIterator->second);
367 }
368 else
369 {
370 ARMNN_LOG(error) << "The CustomAllocator provided with the runtime options doesn't support "
371 "protected memory. Protected mode can't be activated. The backend "
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100372 << id
Jan Eilersc1c872f2021-07-22 13:17:04 +0100373 << " is not going to be used. MemorySource must be MemorySource::DmaBufProtected";
374 continue;
375 }
376 }
377 else
378 {
379 ARMNN_LOG(error) << "Protected mode can't be activated for backend: "
380 << id
381 << " no custom allocator was provided to the runtime options.";
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100382 continue;
383 }
384 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100385 else
386 {
387 // If a custom memory allocator is provided make the backend use that instead of the default
388 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end())
389 {
390 std::string err;
391 if (!backend->UseCustomMemoryAllocator(customAllocatorMapIterator->second, err))
392 {
393 ARMNN_LOG(error) << "The backend "
394 << id
395 << " reported an error when trying to use the provided custom allocator."
396 " Backend won't be used."
397 << " ErrorMsg: " << err;
398 continue;
399 }
400 // No errors so register the Custom Allocator with the BackendRegistry
401 BackendRegistryInstance().RegisterAllocator(id, customAllocatorMapIterator->second);
402 }
403 }
Sadik Armaganb8a26d82021-10-04 15:13:11 +0100404
405 // check if custom memory optimizer strategy map is set
406 if (!options.m_MemoryOptimizerStrategyMap.empty())
407 {
408 auto customMemoryOptimizerStrategyMapIterator = options.m_MemoryOptimizerStrategyMap.find(id);
409 // if a memory optimizer strategy is provided make the backend use that instead of the default
410 if (customMemoryOptimizerStrategyMapIterator != options.m_MemoryOptimizerStrategyMap.end())
411 {
412 // no errors.. register the memory optimizer strategy with the BackendRegistry
413 BackendRegistryInstance().RegisterMemoryOptimizerStrategy(
414 id, customMemoryOptimizerStrategyMapIterator->second);
415
416 ARMNN_LOG(info) << "MemoryOptimizerStrategy "
417 << customMemoryOptimizerStrategyMapIterator->second->GetName()
418 << " set for the backend " << id << ".";
419 }
420 }
421 else
422 {
423 // check if to use one of the existing memory optimizer strategies is set
424 std::string memoryOptimizerStrategyName = "";
425 ParseOptions(options.m_BackendOptions, id, [&](std::string name, const BackendOptions::Var& value)
426 {
427 if (name == "MemoryOptimizerStrategy")
428 {
429 memoryOptimizerStrategyName = ParseStringBackendOption(value, "");
430 }
431 });
432 if (memoryOptimizerStrategyName != "")
433 {
Jim Flynne1fdd282021-10-26 21:26:10 +0100434 std::shared_ptr<IMemoryOptimizerStrategy> strategy =
435 GetMemoryOptimizerStrategy(memoryOptimizerStrategyName);
436
437 if (!strategy)
Sadik Armaganb8a26d82021-10-04 15:13:11 +0100438 {
Jim Flynne1fdd282021-10-26 21:26:10 +0100439 ARMNN_LOG(warning) << "MemoryOptimizerStrategy: " << memoryOptimizerStrategyName
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000440 << " was not found.";
Jim Flynne1fdd282021-10-26 21:26:10 +0100441 }
442 else
443 {
444 using BackendCapability = BackendOptions::BackendOption;
445 auto strategyType = GetMemBlockStrategyTypeName(strategy->GetMemBlockStrategyType());
446 BackendCapability memOptimizeStrategyCapability {strategyType, true};
447 if (HasCapability(memOptimizeStrategyCapability, id))
448 {
449 BackendRegistryInstance().RegisterMemoryOptimizerStrategy(id, strategy);
450
451 ARMNN_LOG(info) << "MemoryOptimizerStrategy: "
452 << memoryOptimizerStrategyName << " set for the backend " << id << ".";
453 }
454 else
455 {
456 ARMNN_LOG(warning) << "Backend "
457 << id
458 << " does not have multi-axis packing capability and cannot support"
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000459 << "MemoryOptimizerStrategy: " << memoryOptimizerStrategyName << ".";
Jim Flynne1fdd282021-10-26 21:26:10 +0100460 }
Sadik Armaganb8a26d82021-10-04 15:13:11 +0100461 }
462 }
463 }
464
David Beck1b61be52018-11-08 09:19:14 +0000465 auto context = backend->CreateBackendContext(options);
466
467 // backends are allowed to return nullptrs if they
468 // don't wish to create a backend specific context
469 if (context)
470 {
471 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
472 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000473 supportedBackends.emplace(id);
Colm Donelan1aff3932020-02-05 17:48:59 +0000474
475 unique_ptr<armnn::profiling::IBackendProfiling> profilingIface =
476 std::make_unique<armnn::profiling::BackendProfiling>(armnn::profiling::BackendProfiling(
Sadik Armagan3184c902020-03-18 10:57:30 +0000477 options, m_ProfilingService, id));
Colm Donelan1aff3932020-02-05 17:48:59 +0000478
479 // Backends may also provide a profiling context. Ask for it now.
480 auto profilingContext = backend->CreateBackendProfilingContext(options, profilingIface);
481 // Backends that don't support profiling will return a null profiling context.
482 if (profilingContext)
483 {
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100484 // Pass the context onto the profiling service.
485 m_ProfilingService.AddBackendProfilingContext(id, profilingContext);
Colm Donelan1aff3932020-02-05 17:48:59 +0000486 }
David Beck1b61be52018-11-08 09:19:14 +0000487 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000488 catch (const BackendUnavailableException&)
489 {
490 // Ignore backends which are unavailable
491 }
David Beck1b61be52018-11-08 09:19:14 +0000492 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100493
Finn Williams45a73622020-05-15 18:41:05 +0100494 BackendRegistryInstance().SetProfilingService(m_ProfilingService);
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100495 // pass configuration info to the profiling service
496 m_ProfilingService.ConfigureProfilingService(options.m_ProfilingOptions);
Jim Flynn6398a982020-05-27 17:05:21 +0100497 if (options.m_ProfilingOptions.m_EnableProfiling)
498 {
499 // try to wait for the profiling service to initialise
500 m_ProfilingService.WaitForProfilingServiceActivation(3000);
501 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100502
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000503 m_DeviceSpec.AddSupportedBackends(supportedBackends);
alered01a7227ac2020-05-07 14:58:29 +0100504
505 ARMNN_LOG(info) << "Initialization time: " << std::setprecision(2)
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000506 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms.";
surmeh01bceff2f2018-03-29 16:29:27 +0100507}
508
Kevin Mayd92a6e42021-02-04 10:27:41 +0000509RuntimeImpl::~RuntimeImpl()
surmeh01bceff2f2018-03-29 16:29:27 +0100510{
Jan Eilers17d34da2021-12-08 16:15:12 +0000511 const auto startTime = armnn::GetTimeNow();
surmeh01bceff2f2018-03-29 16:29:27 +0100512 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100513 try
514 {
515 // Coverity fix: The following code may throw an exception of type std::length_error.
516 std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
517 std::back_inserter(networkIDs),
518 [](const auto &pair) { return pair.first; });
519 }
520 catch (const std::exception& e)
521 {
522 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
523 // exception of type std::length_error.
524 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
525 std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
526 << "\nSome of the loaded networks may not be unloaded" << std::endl;
527 }
528 // We then proceed to unload all the networks which IDs have been appended to the list
529 // up to the point the exception was thrown (if any).
surmeh01bceff2f2018-03-29 16:29:27 +0100530
531 for (auto networkID : networkIDs)
532 {
surmeh013537c2c2018-05-18 16:31:43 +0100533 try
534 {
535 // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
536 // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
537 UnloadNetwork(networkID);
538 }
539 catch (const std::exception& e)
540 {
541 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
542 // exception of type std::length_error.
543 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
544 std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
545 << std::endl;
546 }
telsoa014fcda012018-03-09 14:13:49 +0000547 }
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000548
549 // Clear all dynamic backends.
550 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
551 m_DeviceSpec.ClearDynamicBackends();
Colm Donelan1aff3932020-02-05 17:48:59 +0000552 m_BackendContexts.clear();
Finn Williams45a73622020-05-15 18:41:05 +0100553
554 BackendRegistryInstance().SetProfilingService(armnn::EmptyOptional());
alered01a7227ac2020-05-07 14:58:29 +0100555 ARMNN_LOG(info) << "Shutdown time: " << std::setprecision(2)
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000556 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms.";
telsoa014fcda012018-03-09 14:13:49 +0000557}
558
Kevin Mayd92a6e42021-02-04 10:27:41 +0000559LoadedNetwork* RuntimeImpl::GetLoadedNetworkPtr(NetworkId networkId) const
surmeh013537c2c2018-05-18 16:31:43 +0100560{
561 std::lock_guard<std::mutex> lockGuard(m_Mutex);
562 return m_LoadedNetworks.at(networkId).get();
563}
564
Kevin Mayd92a6e42021-02-04 10:27:41 +0000565TensorInfo RuntimeImpl::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
telsoa014fcda012018-03-09 14:13:49 +0000566{
surmeh013537c2c2018-05-18 16:31:43 +0100567 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000568}
569
Kevin Mayd92a6e42021-02-04 10:27:41 +0000570TensorInfo RuntimeImpl::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
telsoa014fcda012018-03-09 14:13:49 +0000571{
surmeh013537c2c2018-05-18 16:31:43 +0100572 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000573}
574
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000575std::vector<ImportedInputId> RuntimeImpl::ImportInputs(NetworkId networkId, const InputTensors& inputTensors,
576 MemorySource forceImportMemorySource)
Finn Williamsf37b9702021-09-01 18:06:04 +0100577{
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000578 return GetLoadedNetworkPtr(networkId)->ImportInputs(inputTensors, forceImportMemorySource);
Finn Williamsf37b9702021-09-01 18:06:04 +0100579}
580
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000581std::vector<ImportedOutputId> RuntimeImpl::ImportOutputs(NetworkId networkId, const OutputTensors& outputTensors,
582 MemorySource forceImportMemorySource)
Finn Williams8636bc72021-10-02 15:06:39 +0100583{
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000584 return GetLoadedNetworkPtr(networkId)->ImportOutputs(outputTensors, forceImportMemorySource);
Finn Williams8636bc72021-10-02 15:06:39 +0100585}
Finn Williamsf37b9702021-09-01 18:06:04 +0100586
Finn Williams8636bc72021-10-02 15:06:39 +0100587void RuntimeImpl::ClearImportedInputs(NetworkId networkId, const std::vector<ImportedInputId> inputIds)
588{
589 return GetLoadedNetworkPtr(networkId)->ClearImportedInputs(inputIds);
590}
591void RuntimeImpl::ClearImportedOutputs(NetworkId networkId, const std::vector<ImportedOutputId> outputIds)
592{
593 return GetLoadedNetworkPtr(networkId)->ClearImportedOutputs(outputIds);
594}
Derek Lamberti03614f62018-10-02 15:52:46 +0100595
Kevin Mayd92a6e42021-02-04 10:27:41 +0000596Status RuntimeImpl::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100597 const InputTensors& inputTensors,
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000598 const OutputTensors& outputTensors,
599 std::vector<ImportedInputId> preImportedInputIds,
600 std::vector<ImportedOutputId> preImportedOutputIds)
telsoa014fcda012018-03-09 14:13:49 +0000601{
Jan Eilers17d34da2021-12-08 16:15:12 +0000602 const auto startTime = armnn::GetTimeNow();
603
surmeh013537c2c2018-05-18 16:31:43 +0100604 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100605
606 if (!loadedNetwork)
607 {
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000608 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100609 return Status::Failure;
610 }
611 if (loadedNetwork->IsAsyncEnabled())
612 {
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000613 ARMNN_LOG(error) << "Network " << networkId << " is async enabled.";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100614 return Status::Failure;
615 }
Narumol Prangnawarat5b4d0d52020-06-23 11:45:56 +0100616 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
617
618 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "EnqueueWorkload");
Derek Lamberti03614f62018-10-02 15:52:46 +0100619
620 static thread_local NetworkId lastId = networkId;
621 if (lastId != networkId)
622 {
623 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
624 {
625 network->FreeWorkingMemory();
626 });
627 }
628 lastId=networkId;
629
Narumol Prangnawarate2af6f42022-01-28 17:59:18 +0000630 auto status = loadedNetwork->EnqueueWorkload(inputTensors, outputTensors,
631 preImportedInputIds, preImportedOutputIds);
Jan Eilers17d34da2021-12-08 16:15:12 +0000632
633 ARMNN_LOG(info) << "Execution time: " << std::setprecision(2)
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000634 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms.";
Jan Eilers17d34da2021-12-08 16:15:12 +0000635
Narumol Prangnawaratec5463d2022-02-04 17:50:20 +0000636 // Call After EnqueueWorkload events
637 for (auto&& context : m_BackendContexts)
638 {
639 context.second->AfterEnqueueWorkload(networkId);
640 }
641
Jan Eilers17d34da2021-12-08 16:15:12 +0000642 return status;
telsoa014fcda012018-03-09 14:13:49 +0000643}
644
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100645Status RuntimeImpl::Execute(IWorkingMemHandle& iWorkingMemHandle,
646 const InputTensors& inputTensors,
Finn Williamsf37b9702021-09-01 18:06:04 +0100647 const OutputTensors& outputTensors,
Finn Williams8636bc72021-10-02 15:06:39 +0100648 std::vector<ImportedInputId> preImportedInputs,
649 std::vector<ImportedOutputId> preImportedOutputs)
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100650{
Jan Eilers17d34da2021-12-08 16:15:12 +0000651 const auto startTime = armnn::GetTimeNow();
652
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100653 NetworkId networkId = iWorkingMemHandle.GetNetworkId();
654 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
655
656 if (!loadedNetwork)
657 {
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000658 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100659 return Status::Failure;
660 }
661 if (!loadedNetwork->IsAsyncEnabled())
662 {
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000663 ARMNN_LOG(error) << "Attempting execute " << networkId << " when it is not async enabled.";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100664 return Status::Failure;
665 }
666 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
667
668 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "Execute");
669
Jan Eilers17d34da2021-12-08 16:15:12 +0000670 auto status = loadedNetwork->Execute(inputTensors,
671 outputTensors,
672 iWorkingMemHandle,
673 preImportedInputs,
674 preImportedOutputs);
675
676 ARMNN_LOG(info) << "Execution time: " << std::setprecision(2)
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000677 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms.";
Jan Eilers17d34da2021-12-08 16:15:12 +0000678
679 return status;
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100680}
681
682/// Create a new unique WorkingMemHandle object. Create multiple handles if you wish to have
683/// overlapped Execution by calling this function from different threads.
684std::unique_ptr<IWorkingMemHandle> RuntimeImpl::CreateWorkingMemHandle(NetworkId networkId)
685{
686 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
687
688 if (!loadedNetwork)
689 {
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000690 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100691 return nullptr;
692 }
693 if (!loadedNetwork->IsAsyncEnabled())
694 {
Sadik Armagan4a0844d2022-01-26 09:57:05 +0000695 ARMNN_LOG(error) << "Network " << networkId << " is not async enabled.";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100696 return nullptr;
697 }
698 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
699
700 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "CreateWorkingMemHandle");
701
702 static thread_local NetworkId lastId = networkId;
703 if (lastId != networkId)
704 {
705 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
706 {
707 network->FreeWorkingMemory();
708 });
709 }
710 lastId=networkId;
711
712 return loadedNetwork->CreateWorkingMemHandle(networkId);
713}
714
Kevin Mayd92a6e42021-02-04 10:27:41 +0000715void RuntimeImpl::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000716{
717 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
718 loadedNetwork->RegisterDebugCallback(func);
719}
720
Kevin Mayd92a6e42021-02-04 10:27:41 +0000721void RuntimeImpl::LoadDynamicBackends(const std::string& overrideBackendPath)
Matteo Martincighe54aa062019-08-05 14:12:11 +0100722{
723 // Get the paths where to load the dynamic backends from
724 std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
725
726 // Get the shared objects to try to load as dynamic backends
727 std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
728
729 // Create a list of dynamic backends
Matteo Martincigh0c2b2892019-08-05 14:12:11 +0100730 m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
731
732 // Register the dynamic backends in the backend registry
Matteo Martincigh89533902019-08-15 12:08:06 +0100733 BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
734
735 // Add the registered dynamic backend ids to the list of supported backends
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000736 m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
telsoa014fcda012018-03-09 14:13:49 +0000737}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100738
739} // namespace armnn