blob: 50068ebe36c207c993937965ad3a8dfe71f03216 [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>
Sadik Armaganb8a26d82021-10-04 15:13:11 +010015#include <backendsCommon/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
70TensorInfo IRuntime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
71{
72 return pRuntimeImpl->GetInputTensorInfo(networkId, layerId);
73}
74
75TensorInfo IRuntime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
76{
77 return pRuntimeImpl->GetOutputTensorInfo(networkId, layerId);
78}
79
Finn Williamsf37b9702021-09-01 18:06:04 +010080std::vector<ImportedInputId> IRuntime::ImportInputs(NetworkId networkId, const InputTensors& inputTensors)
81{
82 return pRuntimeImpl->ImportInputs(networkId, inputTensors);
83}
84
85
Kevin Mayd92a6e42021-02-04 10:27:41 +000086Status IRuntime::EnqueueWorkload(NetworkId networkId,
87 const InputTensors& inputTensors,
88 const OutputTensors& outputTensors)
89{
90 return pRuntimeImpl->EnqueueWorkload(networkId, inputTensors, outputTensors);
91}
92
Mike Kelly55a8ffd2021-04-07 20:10:49 +010093Status IRuntime::Execute(IWorkingMemHandle& workingMemHandle,
94 const InputTensors& inputTensors,
Finn Williamsf37b9702021-09-01 18:06:04 +010095 const OutputTensors& outputTensors,
96 std::vector<ImportedInputId> preImportedInputs)
Mike Kelly55a8ffd2021-04-07 20:10:49 +010097{
Finn Williamsf37b9702021-09-01 18:06:04 +010098 return pRuntimeImpl->Execute(workingMemHandle, inputTensors, outputTensors, preImportedInputs);
Mike Kelly55a8ffd2021-04-07 20:10:49 +010099}
100
Kevin Mayd92a6e42021-02-04 10:27:41 +0000101Status IRuntime::UnloadNetwork(NetworkId networkId)
102{
103 return pRuntimeImpl->UnloadNetwork(networkId);
104}
105
106const IDeviceSpec& IRuntime::GetDeviceSpec() const
107{
108 return pRuntimeImpl->GetDeviceSpec();
109}
110
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100111std::unique_ptr<IWorkingMemHandle> IRuntime::CreateWorkingMemHandle(NetworkId networkId)
112{
113 return pRuntimeImpl->CreateWorkingMemHandle(networkId);
114}
115
Kevin Mayd92a6e42021-02-04 10:27:41 +0000116const std::shared_ptr<IProfiler> IRuntime::GetProfiler(NetworkId networkId) const
117{
118 return pRuntimeImpl->GetProfiler(networkId);
119}
120
121void IRuntime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
122{
123 return pRuntimeImpl->RegisterDebugCallback(networkId, func);
124}
125
126int RuntimeImpl::GenerateNetworkId()
telsoa014fcda012018-03-09 14:13:49 +0000127{
128 return m_NetworkIdCounter++;
129}
130
Kevin Mayd92a6e42021-02-04 10:27:41 +0000131Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr inNetwork)
telsoa014fcda012018-03-09 14:13:49 +0000132{
telsoa01c577f2c2018-08-31 09:22:23 +0100133 std::string ignoredErrorMessage;
134 return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
135}
136
Kevin Mayd92a6e42021-02-04 10:27:41 +0000137Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut,
138 IOptimizedNetworkPtr inNetwork,
139 std::string& errorMessage)
David Monahan4f1e8e42019-09-04 09:22:10 +0100140{
Jan Eilersc1c872f2021-07-22 13:17:04 +0100141 INetworkProperties networkProperties(
142 false, MemorySource::Undefined, MemorySource::Undefined);
David Monahan4f1e8e42019-09-04 09:22:10 +0100143 return LoadNetwork(networkIdOut, std::move(inNetwork), errorMessage, networkProperties);
144}
145
Kevin Mayd92a6e42021-02-04 10:27:41 +0000146Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut,
147 IOptimizedNetworkPtr inNetwork,
148 std::string& errorMessage,
149 const INetworkProperties& networkProperties)
telsoa01c577f2c2018-08-31 09:22:23 +0100150{
telsoa014fcda012018-03-09 14:13:49 +0000151 IOptimizedNetwork* rawNetwork = inNetwork.release();
David Beck1b61be52018-11-08 09:19:14 +0000152
153 networkIdOut = GenerateNetworkId();
154
155 for (auto&& context : m_BackendContexts)
156 {
157 context.second->BeforeLoadNetwork(networkIdOut);
158 }
159
telsoa014fcda012018-03-09 14:13:49 +0000160 unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000161 std::unique_ptr<IOptimizedNetwork>(rawNetwork),
David Monahan4f1e8e42019-09-04 09:22:10 +0100162 errorMessage,
Sadik Armagan3184c902020-03-18 10:57:30 +0000163 networkProperties,
Finn Williamsf364d532021-06-09 17:07:33 +0100164 m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +0000165
166 if (!loadedNetwork)
167 {
168 return Status::Failure;
169 }
170
telsoa01c577f2c2018-08-31 09:22:23 +0100171 {
172 std::lock_guard<std::mutex> lockGuard(m_Mutex);
173
174 // Stores the network
175 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
176 }
telsoa014fcda012018-03-09 14:13:49 +0000177
David Beck1b61be52018-11-08 09:19:14 +0000178 for (auto&& context : m_BackendContexts)
179 {
180 context.second->AfterLoadNetwork(networkIdOut);
181 }
182
Sadik Armagan3184c902020-03-18 10:57:30 +0000183 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000184 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000185 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_LOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000186 }
187
telsoa014fcda012018-03-09 14:13:49 +0000188 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +0000189}
190
Kevin Mayd92a6e42021-02-04 10:27:41 +0000191Status RuntimeImpl::UnloadNetwork(NetworkId networkId)
telsoa014fcda012018-03-09 14:13:49 +0000192{
David Beck1b61be52018-11-08 09:19:14 +0000193 bool unloadOk = true;
194 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +0000195 {
David Beck1b61be52018-11-08 09:19:14 +0000196 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +0000197 }
David Beck1b61be52018-11-08 09:19:14 +0000198
199 if (!unloadOk)
200 {
Kevin Mayd92a6e42021-02-04 10:27:41 +0000201 ARMNN_LOG(warning) << "RuntimeImpl::UnloadNetwork(): failed to unload "
Derek Lamberti08446972019-11-26 16:38:31 +0000202 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
David Beck1b61be52018-11-08 09:19:14 +0000203 return Status::Failure;
204 }
David Beck9efb57d2018-11-05 13:40:33 +0000205
Jim Flynnf7713212020-07-14 09:50:59 +0100206 std::unique_ptr<profiling::TimelineUtilityMethods> timelineUtils =
207 profiling::TimelineUtilityMethods::GetTimelineUtils(m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +0000208 {
telsoa01c577f2c2018-08-31 09:22:23 +0100209 std::lock_guard<std::mutex> lockGuard(m_Mutex);
210
Jim Flynnf7713212020-07-14 09:50:59 +0100211 // If timeline recording is on mark the Network end of life
212 if (timelineUtils)
213 {
214 auto search = m_LoadedNetworks.find(networkId);
215 if (search != m_LoadedNetworks.end())
216 {
217 profiling::ProfilingGuid networkGuid = search->second->GetNetworkGuid();
218 timelineUtils->RecordEvent(networkGuid,
219 profiling::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
220 }
221 }
telsoa01c577f2c2018-08-31 09:22:23 +0100222 if (m_LoadedNetworks.erase(networkId) == 0)
223 {
Kevin Mayd92a6e42021-02-04 10:27:41 +0000224 ARMNN_LOG(warning) << "WARNING: RuntimeImpl::UnloadNetwork(): " << networkId << " not found!";
telsoa01c577f2c2018-08-31 09:22:23 +0100225 return Status::Failure;
226 }
Sadik Armagan3184c902020-03-18 10:57:30 +0000227
228 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000229 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000230 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_UNLOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000231 }
David Beck1b61be52018-11-08 09:19:14 +0000232 }
David Beck9efb57d2018-11-05 13:40:33 +0000233
David Beck1b61be52018-11-08 09:19:14 +0000234 for (auto&& context : m_BackendContexts)
235 {
236 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100237 }
238
Kevin Mayd92a6e42021-02-04 10:27:41 +0000239 ARMNN_LOG(debug) << "RuntimeImpl::UnloadNetwork(): Unloaded network with ID: " << networkId;
telsoa014fcda012018-03-09 14:13:49 +0000240 return Status::Success;
241}
242
Kevin Mayd92a6e42021-02-04 10:27:41 +0000243const std::shared_ptr<IProfiler> RuntimeImpl::GetProfiler(NetworkId networkId) const
telsoa01c577f2c2018-08-31 09:22:23 +0100244{
245 auto it = m_LoadedNetworks.find(networkId);
246 if (it != m_LoadedNetworks.end())
247 {
248 auto& loadedNetwork = it->second;
249 return loadedNetwork->GetProfiler();
250 }
251
252 return nullptr;
253}
254
Kevin Mayd92a6e42021-02-04 10:27:41 +0000255void RuntimeImpl::ReportStructure() // armnn::profiling::IProfilingService& profilingService as param
Keith Davis33ed2212020-03-30 10:43:41 +0100256{
257 // No-op for the time being, but this may be useful in future to have the profilingService available
258 // if (profilingService.IsProfilingEnabled()){}
259
260 LoadedNetworks::iterator it = m_LoadedNetworks.begin();
261 while (it != m_LoadedNetworks.end())
262 {
263 auto& loadedNetwork = it->second;
264 loadedNetwork->SendNetworkStructure();
265 // Increment the Iterator to point to next entry
266 it++;
267 }
268}
269
Kevin Mayd92a6e42021-02-04 10:27:41 +0000270RuntimeImpl::RuntimeImpl(const IRuntime::CreationOptions& options)
Keith Davis33ed2212020-03-30 10:43:41 +0100271 : m_NetworkIdCounter(0),
272 m_ProfilingService(*this)
telsoa014fcda012018-03-09 14:13:49 +0000273{
alered01a7227ac2020-05-07 14:58:29 +0100274 const auto start_time = armnn::GetTimeNow();
Derek Lamberti08446972019-11-26 16:38:31 +0000275 ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
Keith Davis33ed2212020-03-30 10:43:41 +0100276 if ( options.m_ProfilingOptions.m_TimelineEnabled && !options.m_ProfilingOptions.m_EnableProfiling )
277 {
Jan Eilersc1c872f2021-07-22 13:17:04 +0100278 throw RuntimeException(
279 "It is not possible to enable timeline reporting without profiling being enabled");
Keith Davis33ed2212020-03-30 10:43:41 +0100280 }
281
Matteo Martincighe54aa062019-08-05 14:12:11 +0100282 // Load any available/compatible dynamic backend before the runtime
283 // goes through the backend registry
284 LoadDynamicBackends(options.m_DynamicBackendsPath);
285
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000286 BackendIdSet supportedBackends;
David Beck1b61be52018-11-08 09:19:14 +0000287 for (const auto& id : BackendRegistryInstance().GetBackendIds())
288 {
289 // Store backend contexts for the supported ones
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000290 try {
David Beck1b61be52018-11-08 09:19:14 +0000291 auto factoryFun = BackendRegistryInstance().GetFactory(id);
Colm Donelan380c1a02021-08-17 00:52:23 +0100292 ARMNN_ASSERT(factoryFun != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000293 auto backend = factoryFun();
Colm Donelan380c1a02021-08-17 00:52:23 +0100294 ARMNN_ASSERT(backend != nullptr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100295 ARMNN_ASSERT(backend.get() != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000296
Jan Eilersc1c872f2021-07-22 13:17:04 +0100297 auto customAllocatorMapIterator = options.m_CustomAllocatorMap.find(id);
Francis Murtagh62573b62021-08-12 11:55:21 +0100298 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end() &&
299 customAllocatorMapIterator->second == nullptr)
300 {
Colm Donelan380c1a02021-08-17 00:52:23 +0100301 // We need to manually clean up the dynamic backends before throwing an exception.
302 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
303 m_DeviceSpec.ClearDynamicBackends();
Francis Murtagh62573b62021-08-12 11:55:21 +0100304 throw armnn::Exception("Allocator associated with id " + id.Get() + " is null");
305 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100306
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100307 // If the runtime is created in protected mode only add backends that support this mode
308 if (options.m_ProtectedMode)
309 {
310 // check if backend supports ProtectedMode
311 using BackendCapability = BackendOptions::BackendOption;
312 BackendCapability protectedContentCapability {"ProtectedContentAllocation", true};
313 if (!HasCapability(protectedContentCapability, id))
314 {
315 // Protected Content Allocation is not supported by the backend
316 // backend should not be registered
317 ARMNN_LOG(warning) << "Backend "
318 << id
319 << " is not registered as does not support protected content allocation \n";
320 continue;
321 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100322 // The user is responsible to provide a custom memory allocator which allows to allocate
323 // protected memory
324 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end())
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100325 {
Jan Eilersc1c872f2021-07-22 13:17:04 +0100326 std::string err;
327 if (customAllocatorMapIterator->second->GetMemorySourceType()
328 == armnn::MemorySource::DmaBufProtected)
329 {
330 if (!backend->UseCustomMemoryAllocator(customAllocatorMapIterator->second, err))
331 {
332 ARMNN_LOG(error) << "The backend "
333 << id
334 << " reported an error when entering protected mode. Backend won't be"
335 << " used. ErrorMsg: " << err;
336 continue;
337 }
338 // No errors so register the Custom Allocator with the BackendRegistry
339 BackendRegistryInstance().RegisterAllocator(id, customAllocatorMapIterator->second);
340 }
341 else
342 {
343 ARMNN_LOG(error) << "The CustomAllocator provided with the runtime options doesn't support "
344 "protected memory. Protected mode can't be activated. The backend "
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100345 << id
Jan Eilersc1c872f2021-07-22 13:17:04 +0100346 << " is not going to be used. MemorySource must be MemorySource::DmaBufProtected";
347 continue;
348 }
349 }
350 else
351 {
352 ARMNN_LOG(error) << "Protected mode can't be activated for backend: "
353 << id
354 << " no custom allocator was provided to the runtime options.";
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100355 continue;
356 }
357 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100358 else
359 {
360 // If a custom memory allocator is provided make the backend use that instead of the default
361 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end())
362 {
363 std::string err;
364 if (!backend->UseCustomMemoryAllocator(customAllocatorMapIterator->second, err))
365 {
366 ARMNN_LOG(error) << "The backend "
367 << id
368 << " reported an error when trying to use the provided custom allocator."
369 " Backend won't be used."
370 << " ErrorMsg: " << err;
371 continue;
372 }
373 // No errors so register the Custom Allocator with the BackendRegistry
374 BackendRegistryInstance().RegisterAllocator(id, customAllocatorMapIterator->second);
375 }
376 }
Sadik Armaganb8a26d82021-10-04 15:13:11 +0100377
378 // check if custom memory optimizer strategy map is set
379 if (!options.m_MemoryOptimizerStrategyMap.empty())
380 {
381 auto customMemoryOptimizerStrategyMapIterator = options.m_MemoryOptimizerStrategyMap.find(id);
382 // if a memory optimizer strategy is provided make the backend use that instead of the default
383 if (customMemoryOptimizerStrategyMapIterator != options.m_MemoryOptimizerStrategyMap.end())
384 {
385 // no errors.. register the memory optimizer strategy with the BackendRegistry
386 BackendRegistryInstance().RegisterMemoryOptimizerStrategy(
387 id, customMemoryOptimizerStrategyMapIterator->second);
388
389 ARMNN_LOG(info) << "MemoryOptimizerStrategy "
390 << customMemoryOptimizerStrategyMapIterator->second->GetName()
391 << " set for the backend " << id << ".";
392 }
393 }
394 else
395 {
396 // check if to use one of the existing memory optimizer strategies is set
397 std::string memoryOptimizerStrategyName = "";
398 ParseOptions(options.m_BackendOptions, id, [&](std::string name, const BackendOptions::Var& value)
399 {
400 if (name == "MemoryOptimizerStrategy")
401 {
402 memoryOptimizerStrategyName = ParseStringBackendOption(value, "");
403 }
404 });
405 if (memoryOptimizerStrategyName != "")
406 {
407 MemoryOptimizerStrategyLibrary memoryOptimizerStrategyLibrary;
408 if (memoryOptimizerStrategyLibrary.SetMemoryOptimizerStrategy(id, memoryOptimizerStrategyName))
409 {
410 ARMNN_LOG(info) << "MemoryOptimizerStrategy "
411 << memoryOptimizerStrategyName << " set for the backend " << id << ".";
412 }
413 }
414 }
415
David Beck1b61be52018-11-08 09:19:14 +0000416 auto context = backend->CreateBackendContext(options);
417
418 // backends are allowed to return nullptrs if they
419 // don't wish to create a backend specific context
420 if (context)
421 {
422 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
423 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000424 supportedBackends.emplace(id);
Colm Donelan1aff3932020-02-05 17:48:59 +0000425
426 unique_ptr<armnn::profiling::IBackendProfiling> profilingIface =
427 std::make_unique<armnn::profiling::BackendProfiling>(armnn::profiling::BackendProfiling(
Sadik Armagan3184c902020-03-18 10:57:30 +0000428 options, m_ProfilingService, id));
Colm Donelan1aff3932020-02-05 17:48:59 +0000429
430 // Backends may also provide a profiling context. Ask for it now.
431 auto profilingContext = backend->CreateBackendProfilingContext(options, profilingIface);
432 // Backends that don't support profiling will return a null profiling context.
433 if (profilingContext)
434 {
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100435 // Pass the context onto the profiling service.
436 m_ProfilingService.AddBackendProfilingContext(id, profilingContext);
Colm Donelan1aff3932020-02-05 17:48:59 +0000437 }
David Beck1b61be52018-11-08 09:19:14 +0000438 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000439 catch (const BackendUnavailableException&)
440 {
441 // Ignore backends which are unavailable
442 }
David Beck1b61be52018-11-08 09:19:14 +0000443 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100444
Finn Williams45a73622020-05-15 18:41:05 +0100445 BackendRegistryInstance().SetProfilingService(m_ProfilingService);
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100446 // pass configuration info to the profiling service
447 m_ProfilingService.ConfigureProfilingService(options.m_ProfilingOptions);
Jim Flynn6398a982020-05-27 17:05:21 +0100448 if (options.m_ProfilingOptions.m_EnableProfiling)
449 {
450 // try to wait for the profiling service to initialise
451 m_ProfilingService.WaitForProfilingServiceActivation(3000);
452 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100453
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000454 m_DeviceSpec.AddSupportedBackends(supportedBackends);
alered01a7227ac2020-05-07 14:58:29 +0100455
456 ARMNN_LOG(info) << "Initialization time: " << std::setprecision(2)
457 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
surmeh01bceff2f2018-03-29 16:29:27 +0100458}
459
Kevin Mayd92a6e42021-02-04 10:27:41 +0000460RuntimeImpl::~RuntimeImpl()
surmeh01bceff2f2018-03-29 16:29:27 +0100461{
alered01a7227ac2020-05-07 14:58:29 +0100462 const auto start_time = armnn::GetTimeNow();
surmeh01bceff2f2018-03-29 16:29:27 +0100463 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100464 try
465 {
466 // Coverity fix: The following code may throw an exception of type std::length_error.
467 std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
468 std::back_inserter(networkIDs),
469 [](const auto &pair) { return pair.first; });
470 }
471 catch (const std::exception& e)
472 {
473 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
474 // exception of type std::length_error.
475 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
476 std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
477 << "\nSome of the loaded networks may not be unloaded" << std::endl;
478 }
479 // We then proceed to unload all the networks which IDs have been appended to the list
480 // up to the point the exception was thrown (if any).
surmeh01bceff2f2018-03-29 16:29:27 +0100481
482 for (auto networkID : networkIDs)
483 {
surmeh013537c2c2018-05-18 16:31:43 +0100484 try
485 {
486 // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
487 // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
488 UnloadNetwork(networkID);
489 }
490 catch (const std::exception& e)
491 {
492 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
493 // exception of type std::length_error.
494 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
495 std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
496 << std::endl;
497 }
telsoa014fcda012018-03-09 14:13:49 +0000498 }
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000499
500 // Clear all dynamic backends.
501 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
502 m_DeviceSpec.ClearDynamicBackends();
Colm Donelan1aff3932020-02-05 17:48:59 +0000503 m_BackendContexts.clear();
Finn Williams45a73622020-05-15 18:41:05 +0100504
505 BackendRegistryInstance().SetProfilingService(armnn::EmptyOptional());
alered01a7227ac2020-05-07 14:58:29 +0100506 ARMNN_LOG(info) << "Shutdown time: " << std::setprecision(2)
507 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
telsoa014fcda012018-03-09 14:13:49 +0000508}
509
Kevin Mayd92a6e42021-02-04 10:27:41 +0000510LoadedNetwork* RuntimeImpl::GetLoadedNetworkPtr(NetworkId networkId) const
surmeh013537c2c2018-05-18 16:31:43 +0100511{
512 std::lock_guard<std::mutex> lockGuard(m_Mutex);
513 return m_LoadedNetworks.at(networkId).get();
514}
515
Kevin Mayd92a6e42021-02-04 10:27:41 +0000516TensorInfo RuntimeImpl::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
telsoa014fcda012018-03-09 14:13:49 +0000517{
surmeh013537c2c2018-05-18 16:31:43 +0100518 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000519}
520
Kevin Mayd92a6e42021-02-04 10:27:41 +0000521TensorInfo RuntimeImpl::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
telsoa014fcda012018-03-09 14:13:49 +0000522{
surmeh013537c2c2018-05-18 16:31:43 +0100523 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000524}
525
Finn Williamsf37b9702021-09-01 18:06:04 +0100526std::vector<ImportedInputId> RuntimeImpl::ImportInputs(NetworkId networkId, const InputTensors& inputTensors)
527{
528 return GetLoadedNetworkPtr(networkId)->ImportInputs(inputTensors);
529}
530
531
Derek Lamberti03614f62018-10-02 15:52:46 +0100532
Kevin Mayd92a6e42021-02-04 10:27:41 +0000533Status RuntimeImpl::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100534 const InputTensors& inputTensors,
535 const OutputTensors& outputTensors)
telsoa014fcda012018-03-09 14:13:49 +0000536{
surmeh013537c2c2018-05-18 16:31:43 +0100537 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100538
539 if (!loadedNetwork)
540 {
541 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.\n";
542 return Status::Failure;
543 }
544 if (loadedNetwork->IsAsyncEnabled())
545 {
546 ARMNN_LOG(error) << "Network " << networkId << " is async enabled.\n";
547 return Status::Failure;
548 }
Narumol Prangnawarat5b4d0d52020-06-23 11:45:56 +0100549 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
550
551 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "EnqueueWorkload");
Derek Lamberti03614f62018-10-02 15:52:46 +0100552
553 static thread_local NetworkId lastId = networkId;
554 if (lastId != networkId)
555 {
556 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
557 {
558 network->FreeWorkingMemory();
559 });
560 }
561 lastId=networkId;
562
surmeh013537c2c2018-05-18 16:31:43 +0100563 return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
telsoa014fcda012018-03-09 14:13:49 +0000564}
565
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100566Status RuntimeImpl::Execute(IWorkingMemHandle& iWorkingMemHandle,
567 const InputTensors& inputTensors,
Finn Williamsf37b9702021-09-01 18:06:04 +0100568 const OutputTensors& outputTensors,
569 std::vector<ImportedInputId> preImportedInputs)
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100570{
571 NetworkId networkId = iWorkingMemHandle.GetNetworkId();
572 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
573
574 if (!loadedNetwork)
575 {
576 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.\n";
577 return Status::Failure;
578 }
579 if (!loadedNetwork->IsAsyncEnabled())
580 {
Keith Davise813d672021-04-22 10:10:34 +0100581 ARMNN_LOG(error) << "Attempting execute " << networkId << " when it is not async enabled.\n";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100582 return Status::Failure;
583 }
584 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
585
586 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "Execute");
587
Finn Williamsf37b9702021-09-01 18:06:04 +0100588 return loadedNetwork->Execute(inputTensors, outputTensors, iWorkingMemHandle, preImportedInputs);
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100589}
590
591/// Create a new unique WorkingMemHandle object. Create multiple handles if you wish to have
592/// overlapped Execution by calling this function from different threads.
593std::unique_ptr<IWorkingMemHandle> RuntimeImpl::CreateWorkingMemHandle(NetworkId networkId)
594{
595 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
596
597 if (!loadedNetwork)
598 {
599 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.\n";
600 return nullptr;
601 }
602 if (!loadedNetwork->IsAsyncEnabled())
603 {
604 ARMNN_LOG(error) << "Network " << networkId << " is not async enabled.\n";
605 return nullptr;
606 }
607 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
608
609 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "CreateWorkingMemHandle");
610
611 static thread_local NetworkId lastId = networkId;
612 if (lastId != networkId)
613 {
614 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
615 {
616 network->FreeWorkingMemory();
617 });
618 }
619 lastId=networkId;
620
621 return loadedNetwork->CreateWorkingMemHandle(networkId);
622}
623
Kevin Mayd92a6e42021-02-04 10:27:41 +0000624void RuntimeImpl::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000625{
626 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
627 loadedNetwork->RegisterDebugCallback(func);
628}
629
Kevin Mayd92a6e42021-02-04 10:27:41 +0000630void RuntimeImpl::LoadDynamicBackends(const std::string& overrideBackendPath)
Matteo Martincighe54aa062019-08-05 14:12:11 +0100631{
632 // Get the paths where to load the dynamic backends from
633 std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
634
635 // Get the shared objects to try to load as dynamic backends
636 std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
637
638 // Create a list of dynamic backends
Matteo Martincigh0c2b2892019-08-05 14:12:11 +0100639 m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
640
641 // Register the dynamic backends in the backend registry
Matteo Martincigh89533902019-08-15 12:08:06 +0100642 BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
643
644 // Add the registered dynamic backend ids to the list of supported backends
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000645 m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
telsoa014fcda012018-03-09 14:13:49 +0000646}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100647
648} // namespace armnn