blob: 1ccfb4687aeaa85f8fc2b1cd44c3912c5b1e4f56 [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
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
Finn Williams8636bc72021-10-02 15:06:39 +010085std::vector<ImportedOutputId> IRuntime::ImportOutputs(NetworkId networkId, const OutputTensors& outputTensors)
86{
87 return pRuntimeImpl->ImportOutputs(networkId, outputTensors);
88}
89
90void IRuntime::ClearImportedInputs(NetworkId networkId, const std::vector<ImportedInputId> inputIds)
91{
92 return pRuntimeImpl->ClearImportedInputs(networkId, inputIds);
93}
94void IRuntime::ClearImportedOutputs(NetworkId networkId, const std::vector<ImportedOutputId> outputIds)
95{
96 return pRuntimeImpl->ClearImportedOutputs(networkId, outputIds);
97}
Finn Williamsf37b9702021-09-01 18:06:04 +010098
Kevin Mayd92a6e42021-02-04 10:27:41 +000099Status IRuntime::EnqueueWorkload(NetworkId networkId,
100 const InputTensors& inputTensors,
101 const OutputTensors& outputTensors)
102{
103 return pRuntimeImpl->EnqueueWorkload(networkId, inputTensors, outputTensors);
104}
105
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100106Status IRuntime::Execute(IWorkingMemHandle& workingMemHandle,
107 const InputTensors& inputTensors,
Finn Williamsf37b9702021-09-01 18:06:04 +0100108 const OutputTensors& outputTensors,
Finn Williams8636bc72021-10-02 15:06:39 +0100109 std::vector<ImportedInputId> preImportedInputs,
110 std::vector<ImportedOutputId> preImportedOutputs)
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100111{
Finn Williams8636bc72021-10-02 15:06:39 +0100112 return pRuntimeImpl->Execute(workingMemHandle, inputTensors, outputTensors, preImportedInputs, preImportedOutputs);
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100113}
114
Kevin Mayd92a6e42021-02-04 10:27:41 +0000115Status IRuntime::UnloadNetwork(NetworkId networkId)
116{
117 return pRuntimeImpl->UnloadNetwork(networkId);
118}
119
120const IDeviceSpec& IRuntime::GetDeviceSpec() const
121{
122 return pRuntimeImpl->GetDeviceSpec();
123}
124
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100125std::unique_ptr<IWorkingMemHandle> IRuntime::CreateWorkingMemHandle(NetworkId networkId)
126{
127 return pRuntimeImpl->CreateWorkingMemHandle(networkId);
128}
129
Kevin Mayd92a6e42021-02-04 10:27:41 +0000130const std::shared_ptr<IProfiler> IRuntime::GetProfiler(NetworkId networkId) const
131{
132 return pRuntimeImpl->GetProfiler(networkId);
133}
134
135void IRuntime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
136{
137 return pRuntimeImpl->RegisterDebugCallback(networkId, func);
138}
139
140int RuntimeImpl::GenerateNetworkId()
telsoa014fcda012018-03-09 14:13:49 +0000141{
142 return m_NetworkIdCounter++;
143}
144
Kevin Mayd92a6e42021-02-04 10:27:41 +0000145Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr inNetwork)
telsoa014fcda012018-03-09 14:13:49 +0000146{
telsoa01c577f2c2018-08-31 09:22:23 +0100147 std::string ignoredErrorMessage;
148 return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
149}
150
Kevin Mayd92a6e42021-02-04 10:27:41 +0000151Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut,
152 IOptimizedNetworkPtr inNetwork,
153 std::string& errorMessage)
David Monahan4f1e8e42019-09-04 09:22:10 +0100154{
Jan Eilersc1c872f2021-07-22 13:17:04 +0100155 INetworkProperties networkProperties(
156 false, MemorySource::Undefined, MemorySource::Undefined);
David Monahan4f1e8e42019-09-04 09:22:10 +0100157 return LoadNetwork(networkIdOut, std::move(inNetwork), errorMessage, networkProperties);
158}
159
Kevin Mayd92a6e42021-02-04 10:27:41 +0000160Status RuntimeImpl::LoadNetwork(NetworkId& networkIdOut,
161 IOptimizedNetworkPtr inNetwork,
162 std::string& errorMessage,
163 const INetworkProperties& networkProperties)
telsoa01c577f2c2018-08-31 09:22:23 +0100164{
Derek Lambertie155bbf2021-10-13 14:32:12 +0100165 // Register the profiler
166 auto profiler = inNetwork->GetProfiler();
167 ProfilerManager::GetInstance().RegisterProfiler(profiler.get());
168
telsoa014fcda012018-03-09 14:13:49 +0000169 IOptimizedNetwork* rawNetwork = inNetwork.release();
David Beck1b61be52018-11-08 09:19:14 +0000170
171 networkIdOut = GenerateNetworkId();
172
173 for (auto&& context : m_BackendContexts)
174 {
175 context.second->BeforeLoadNetwork(networkIdOut);
176 }
177
telsoa014fcda012018-03-09 14:13:49 +0000178 unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000179 std::unique_ptr<IOptimizedNetwork>(rawNetwork),
David Monahan4f1e8e42019-09-04 09:22:10 +0100180 errorMessage,
Sadik Armagan3184c902020-03-18 10:57:30 +0000181 networkProperties,
Finn Williamsf364d532021-06-09 17:07:33 +0100182 m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +0000183
184 if (!loadedNetwork)
185 {
186 return Status::Failure;
187 }
188
telsoa01c577f2c2018-08-31 09:22:23 +0100189 {
190 std::lock_guard<std::mutex> lockGuard(m_Mutex);
191
192 // Stores the network
193 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
194 }
telsoa014fcda012018-03-09 14:13:49 +0000195
David Beck1b61be52018-11-08 09:19:14 +0000196 for (auto&& context : m_BackendContexts)
197 {
198 context.second->AfterLoadNetwork(networkIdOut);
199 }
200
Sadik Armagan3184c902020-03-18 10:57:30 +0000201 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000202 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000203 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_LOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000204 }
205
telsoa014fcda012018-03-09 14:13:49 +0000206 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +0000207}
208
Kevin Mayd92a6e42021-02-04 10:27:41 +0000209Status RuntimeImpl::UnloadNetwork(NetworkId networkId)
telsoa014fcda012018-03-09 14:13:49 +0000210{
David Beck1b61be52018-11-08 09:19:14 +0000211 bool unloadOk = true;
212 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +0000213 {
David Beck1b61be52018-11-08 09:19:14 +0000214 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +0000215 }
David Beck1b61be52018-11-08 09:19:14 +0000216
217 if (!unloadOk)
218 {
Kevin Mayd92a6e42021-02-04 10:27:41 +0000219 ARMNN_LOG(warning) << "RuntimeImpl::UnloadNetwork(): failed to unload "
Derek Lamberti08446972019-11-26 16:38:31 +0000220 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
David Beck1b61be52018-11-08 09:19:14 +0000221 return Status::Failure;
222 }
David Beck9efb57d2018-11-05 13:40:33 +0000223
Jim Flynnf7713212020-07-14 09:50:59 +0100224 std::unique_ptr<profiling::TimelineUtilityMethods> timelineUtils =
225 profiling::TimelineUtilityMethods::GetTimelineUtils(m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +0000226 {
telsoa01c577f2c2018-08-31 09:22:23 +0100227 std::lock_guard<std::mutex> lockGuard(m_Mutex);
228
Jim Flynnf7713212020-07-14 09:50:59 +0100229 // If timeline recording is on mark the Network end of life
230 if (timelineUtils)
231 {
232 auto search = m_LoadedNetworks.find(networkId);
233 if (search != m_LoadedNetworks.end())
234 {
235 profiling::ProfilingGuid networkGuid = search->second->GetNetworkGuid();
236 timelineUtils->RecordEvent(networkGuid,
237 profiling::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
238 }
239 }
telsoa01c577f2c2018-08-31 09:22:23 +0100240 if (m_LoadedNetworks.erase(networkId) == 0)
241 {
Kevin Mayd92a6e42021-02-04 10:27:41 +0000242 ARMNN_LOG(warning) << "WARNING: RuntimeImpl::UnloadNetwork(): " << networkId << " not found!";
telsoa01c577f2c2018-08-31 09:22:23 +0100243 return Status::Failure;
244 }
Sadik Armagan3184c902020-03-18 10:57:30 +0000245
246 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000247 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000248 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_UNLOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000249 }
David Beck1b61be52018-11-08 09:19:14 +0000250 }
David Beck9efb57d2018-11-05 13:40:33 +0000251
David Beck1b61be52018-11-08 09:19:14 +0000252 for (auto&& context : m_BackendContexts)
253 {
254 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100255 }
256
Derek Lambertie155bbf2021-10-13 14:32:12 +0100257 // Unregister the profiler
258 ProfilerManager::GetInstance().RegisterProfiler(nullptr);
259
Kevin Mayd92a6e42021-02-04 10:27:41 +0000260 ARMNN_LOG(debug) << "RuntimeImpl::UnloadNetwork(): Unloaded network with ID: " << networkId;
telsoa014fcda012018-03-09 14:13:49 +0000261 return Status::Success;
262}
263
Kevin Mayd92a6e42021-02-04 10:27:41 +0000264const std::shared_ptr<IProfiler> RuntimeImpl::GetProfiler(NetworkId networkId) const
telsoa01c577f2c2018-08-31 09:22:23 +0100265{
266 auto it = m_LoadedNetworks.find(networkId);
267 if (it != m_LoadedNetworks.end())
268 {
269 auto& loadedNetwork = it->second;
270 return loadedNetwork->GetProfiler();
271 }
272
273 return nullptr;
274}
275
Kevin Mayd92a6e42021-02-04 10:27:41 +0000276void RuntimeImpl::ReportStructure() // armnn::profiling::IProfilingService& profilingService as param
Keith Davis33ed2212020-03-30 10:43:41 +0100277{
278 // No-op for the time being, but this may be useful in future to have the profilingService available
279 // if (profilingService.IsProfilingEnabled()){}
280
281 LoadedNetworks::iterator it = m_LoadedNetworks.begin();
282 while (it != m_LoadedNetworks.end())
283 {
284 auto& loadedNetwork = it->second;
285 loadedNetwork->SendNetworkStructure();
286 // Increment the Iterator to point to next entry
287 it++;
288 }
289}
290
Kevin Mayd92a6e42021-02-04 10:27:41 +0000291RuntimeImpl::RuntimeImpl(const IRuntime::CreationOptions& options)
Keith Davis33ed2212020-03-30 10:43:41 +0100292 : m_NetworkIdCounter(0),
293 m_ProfilingService(*this)
telsoa014fcda012018-03-09 14:13:49 +0000294{
alered01a7227ac2020-05-07 14:58:29 +0100295 const auto start_time = armnn::GetTimeNow();
Derek Lamberti08446972019-11-26 16:38:31 +0000296 ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
Keith Davis33ed2212020-03-30 10:43:41 +0100297 if ( options.m_ProfilingOptions.m_TimelineEnabled && !options.m_ProfilingOptions.m_EnableProfiling )
298 {
Jan Eilersc1c872f2021-07-22 13:17:04 +0100299 throw RuntimeException(
300 "It is not possible to enable timeline reporting without profiling being enabled");
Keith Davis33ed2212020-03-30 10:43:41 +0100301 }
302
Matteo Martincighe54aa062019-08-05 14:12:11 +0100303 // Load any available/compatible dynamic backend before the runtime
304 // goes through the backend registry
305 LoadDynamicBackends(options.m_DynamicBackendsPath);
306
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000307 BackendIdSet supportedBackends;
David Beck1b61be52018-11-08 09:19:14 +0000308 for (const auto& id : BackendRegistryInstance().GetBackendIds())
309 {
310 // Store backend contexts for the supported ones
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000311 try {
David Beck1b61be52018-11-08 09:19:14 +0000312 auto factoryFun = BackendRegistryInstance().GetFactory(id);
Colm Donelan380c1a02021-08-17 00:52:23 +0100313 ARMNN_ASSERT(factoryFun != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000314 auto backend = factoryFun();
Colm Donelan380c1a02021-08-17 00:52:23 +0100315 ARMNN_ASSERT(backend != nullptr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100316 ARMNN_ASSERT(backend.get() != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000317
Jan Eilersc1c872f2021-07-22 13:17:04 +0100318 auto customAllocatorMapIterator = options.m_CustomAllocatorMap.find(id);
Francis Murtagh62573b62021-08-12 11:55:21 +0100319 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end() &&
320 customAllocatorMapIterator->second == nullptr)
321 {
Colm Donelan380c1a02021-08-17 00:52:23 +0100322 // We need to manually clean up the dynamic backends before throwing an exception.
323 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
324 m_DeviceSpec.ClearDynamicBackends();
Francis Murtagh62573b62021-08-12 11:55:21 +0100325 throw armnn::Exception("Allocator associated with id " + id.Get() + " is null");
326 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100327
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100328 // If the runtime is created in protected mode only add backends that support this mode
329 if (options.m_ProtectedMode)
330 {
331 // check if backend supports ProtectedMode
332 using BackendCapability = BackendOptions::BackendOption;
333 BackendCapability protectedContentCapability {"ProtectedContentAllocation", true};
334 if (!HasCapability(protectedContentCapability, id))
335 {
336 // Protected Content Allocation is not supported by the backend
337 // backend should not be registered
338 ARMNN_LOG(warning) << "Backend "
339 << id
340 << " is not registered as does not support protected content allocation \n";
341 continue;
342 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100343 // The user is responsible to provide a custom memory allocator which allows to allocate
344 // protected memory
345 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end())
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100346 {
Jan Eilersc1c872f2021-07-22 13:17:04 +0100347 std::string err;
348 if (customAllocatorMapIterator->second->GetMemorySourceType()
349 == armnn::MemorySource::DmaBufProtected)
350 {
351 if (!backend->UseCustomMemoryAllocator(customAllocatorMapIterator->second, err))
352 {
353 ARMNN_LOG(error) << "The backend "
354 << id
355 << " reported an error when entering protected mode. Backend won't be"
356 << " used. ErrorMsg: " << err;
357 continue;
358 }
359 // No errors so register the Custom Allocator with the BackendRegistry
360 BackendRegistryInstance().RegisterAllocator(id, customAllocatorMapIterator->second);
361 }
362 else
363 {
364 ARMNN_LOG(error) << "The CustomAllocator provided with the runtime options doesn't support "
365 "protected memory. Protected mode can't be activated. The backend "
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100366 << id
Jan Eilersc1c872f2021-07-22 13:17:04 +0100367 << " is not going to be used. MemorySource must be MemorySource::DmaBufProtected";
368 continue;
369 }
370 }
371 else
372 {
373 ARMNN_LOG(error) << "Protected mode can't be activated for backend: "
374 << id
375 << " no custom allocator was provided to the runtime options.";
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100376 continue;
377 }
378 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100379 else
380 {
381 // If a custom memory allocator is provided make the backend use that instead of the default
382 if (customAllocatorMapIterator != options.m_CustomAllocatorMap.end())
383 {
384 std::string err;
385 if (!backend->UseCustomMemoryAllocator(customAllocatorMapIterator->second, err))
386 {
387 ARMNN_LOG(error) << "The backend "
388 << id
389 << " reported an error when trying to use the provided custom allocator."
390 " Backend won't be used."
391 << " ErrorMsg: " << err;
392 continue;
393 }
394 // No errors so register the Custom Allocator with the BackendRegistry
395 BackendRegistryInstance().RegisterAllocator(id, customAllocatorMapIterator->second);
396 }
397 }
Sadik Armaganb8a26d82021-10-04 15:13:11 +0100398
399 // check if custom memory optimizer strategy map is set
400 if (!options.m_MemoryOptimizerStrategyMap.empty())
401 {
402 auto customMemoryOptimizerStrategyMapIterator = options.m_MemoryOptimizerStrategyMap.find(id);
403 // if a memory optimizer strategy is provided make the backend use that instead of the default
404 if (customMemoryOptimizerStrategyMapIterator != options.m_MemoryOptimizerStrategyMap.end())
405 {
406 // no errors.. register the memory optimizer strategy with the BackendRegistry
407 BackendRegistryInstance().RegisterMemoryOptimizerStrategy(
408 id, customMemoryOptimizerStrategyMapIterator->second);
409
410 ARMNN_LOG(info) << "MemoryOptimizerStrategy "
411 << customMemoryOptimizerStrategyMapIterator->second->GetName()
412 << " set for the backend " << id << ".";
413 }
414 }
415 else
416 {
417 // check if to use one of the existing memory optimizer strategies is set
418 std::string memoryOptimizerStrategyName = "";
419 ParseOptions(options.m_BackendOptions, id, [&](std::string name, const BackendOptions::Var& value)
420 {
421 if (name == "MemoryOptimizerStrategy")
422 {
423 memoryOptimizerStrategyName = ParseStringBackendOption(value, "");
424 }
425 });
426 if (memoryOptimizerStrategyName != "")
427 {
Jim Flynne1fdd282021-10-26 21:26:10 +0100428 std::shared_ptr<IMemoryOptimizerStrategy> strategy =
429 GetMemoryOptimizerStrategy(memoryOptimizerStrategyName);
430
431 if (!strategy)
Sadik Armaganb8a26d82021-10-04 15:13:11 +0100432 {
Jim Flynne1fdd282021-10-26 21:26:10 +0100433 ARMNN_LOG(warning) << "MemoryOptimizerStrategy: " << memoryOptimizerStrategyName
434 << " was not found \n";
435 }
436 else
437 {
438 using BackendCapability = BackendOptions::BackendOption;
439 auto strategyType = GetMemBlockStrategyTypeName(strategy->GetMemBlockStrategyType());
440 BackendCapability memOptimizeStrategyCapability {strategyType, true};
441 if (HasCapability(memOptimizeStrategyCapability, id))
442 {
443 BackendRegistryInstance().RegisterMemoryOptimizerStrategy(id, strategy);
444
445 ARMNN_LOG(info) << "MemoryOptimizerStrategy: "
446 << memoryOptimizerStrategyName << " set for the backend " << id << ".";
447 }
448 else
449 {
450 ARMNN_LOG(warning) << "Backend "
451 << id
452 << " does not have multi-axis packing capability and cannot support"
453 << "MemoryOptimizerStrategy: " << memoryOptimizerStrategyName << "\n";
454 }
Sadik Armaganb8a26d82021-10-04 15:13:11 +0100455 }
456 }
457 }
458
David Beck1b61be52018-11-08 09:19:14 +0000459 auto context = backend->CreateBackendContext(options);
460
461 // backends are allowed to return nullptrs if they
462 // don't wish to create a backend specific context
463 if (context)
464 {
465 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
466 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000467 supportedBackends.emplace(id);
Colm Donelan1aff3932020-02-05 17:48:59 +0000468
469 unique_ptr<armnn::profiling::IBackendProfiling> profilingIface =
470 std::make_unique<armnn::profiling::BackendProfiling>(armnn::profiling::BackendProfiling(
Sadik Armagan3184c902020-03-18 10:57:30 +0000471 options, m_ProfilingService, id));
Colm Donelan1aff3932020-02-05 17:48:59 +0000472
473 // Backends may also provide a profiling context. Ask for it now.
474 auto profilingContext = backend->CreateBackendProfilingContext(options, profilingIface);
475 // Backends that don't support profiling will return a null profiling context.
476 if (profilingContext)
477 {
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100478 // Pass the context onto the profiling service.
479 m_ProfilingService.AddBackendProfilingContext(id, profilingContext);
Colm Donelan1aff3932020-02-05 17:48:59 +0000480 }
David Beck1b61be52018-11-08 09:19:14 +0000481 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000482 catch (const BackendUnavailableException&)
483 {
484 // Ignore backends which are unavailable
485 }
David Beck1b61be52018-11-08 09:19:14 +0000486 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100487
Finn Williams45a73622020-05-15 18:41:05 +0100488 BackendRegistryInstance().SetProfilingService(m_ProfilingService);
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100489 // pass configuration info to the profiling service
490 m_ProfilingService.ConfigureProfilingService(options.m_ProfilingOptions);
Jim Flynn6398a982020-05-27 17:05:21 +0100491 if (options.m_ProfilingOptions.m_EnableProfiling)
492 {
493 // try to wait for the profiling service to initialise
494 m_ProfilingService.WaitForProfilingServiceActivation(3000);
495 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100496
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000497 m_DeviceSpec.AddSupportedBackends(supportedBackends);
alered01a7227ac2020-05-07 14:58:29 +0100498
499 ARMNN_LOG(info) << "Initialization time: " << std::setprecision(2)
500 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
surmeh01bceff2f2018-03-29 16:29:27 +0100501}
502
Kevin Mayd92a6e42021-02-04 10:27:41 +0000503RuntimeImpl::~RuntimeImpl()
surmeh01bceff2f2018-03-29 16:29:27 +0100504{
Jan Eilers17d34da2021-12-08 16:15:12 +0000505 const auto startTime = armnn::GetTimeNow();
surmeh01bceff2f2018-03-29 16:29:27 +0100506 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100507 try
508 {
509 // Coverity fix: The following code may throw an exception of type std::length_error.
510 std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
511 std::back_inserter(networkIDs),
512 [](const auto &pair) { return pair.first; });
513 }
514 catch (const std::exception& e)
515 {
516 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
517 // exception of type std::length_error.
518 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
519 std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
520 << "\nSome of the loaded networks may not be unloaded" << std::endl;
521 }
522 // We then proceed to unload all the networks which IDs have been appended to the list
523 // up to the point the exception was thrown (if any).
surmeh01bceff2f2018-03-29 16:29:27 +0100524
525 for (auto networkID : networkIDs)
526 {
surmeh013537c2c2018-05-18 16:31:43 +0100527 try
528 {
529 // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
530 // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
531 UnloadNetwork(networkID);
532 }
533 catch (const std::exception& e)
534 {
535 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
536 // exception of type std::length_error.
537 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
538 std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
539 << std::endl;
540 }
telsoa014fcda012018-03-09 14:13:49 +0000541 }
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000542
543 // Clear all dynamic backends.
544 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
545 m_DeviceSpec.ClearDynamicBackends();
Colm Donelan1aff3932020-02-05 17:48:59 +0000546 m_BackendContexts.clear();
Finn Williams45a73622020-05-15 18:41:05 +0100547
548 BackendRegistryInstance().SetProfilingService(armnn::EmptyOptional());
alered01a7227ac2020-05-07 14:58:29 +0100549 ARMNN_LOG(info) << "Shutdown time: " << std::setprecision(2)
Jan Eilers17d34da2021-12-08 16:15:12 +0000550 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms\n";
telsoa014fcda012018-03-09 14:13:49 +0000551}
552
Kevin Mayd92a6e42021-02-04 10:27:41 +0000553LoadedNetwork* RuntimeImpl::GetLoadedNetworkPtr(NetworkId networkId) const
surmeh013537c2c2018-05-18 16:31:43 +0100554{
555 std::lock_guard<std::mutex> lockGuard(m_Mutex);
556 return m_LoadedNetworks.at(networkId).get();
557}
558
Kevin Mayd92a6e42021-02-04 10:27:41 +0000559TensorInfo RuntimeImpl::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
telsoa014fcda012018-03-09 14:13:49 +0000560{
surmeh013537c2c2018-05-18 16:31:43 +0100561 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000562}
563
Kevin Mayd92a6e42021-02-04 10:27:41 +0000564TensorInfo RuntimeImpl::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
telsoa014fcda012018-03-09 14:13:49 +0000565{
surmeh013537c2c2018-05-18 16:31:43 +0100566 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000567}
568
Finn Williamsf37b9702021-09-01 18:06:04 +0100569std::vector<ImportedInputId> RuntimeImpl::ImportInputs(NetworkId networkId, const InputTensors& inputTensors)
570{
571 return GetLoadedNetworkPtr(networkId)->ImportInputs(inputTensors);
572}
573
Finn Williams8636bc72021-10-02 15:06:39 +0100574std::vector<ImportedOutputId> RuntimeImpl::ImportOutputs(NetworkId networkId, const OutputTensors& outputTensors)
575{
576 return GetLoadedNetworkPtr(networkId)->ImportOutputs(outputTensors);
577}
Finn Williamsf37b9702021-09-01 18:06:04 +0100578
Finn Williams8636bc72021-10-02 15:06:39 +0100579void RuntimeImpl::ClearImportedInputs(NetworkId networkId, const std::vector<ImportedInputId> inputIds)
580{
581 return GetLoadedNetworkPtr(networkId)->ClearImportedInputs(inputIds);
582}
583void RuntimeImpl::ClearImportedOutputs(NetworkId networkId, const std::vector<ImportedOutputId> outputIds)
584{
585 return GetLoadedNetworkPtr(networkId)->ClearImportedOutputs(outputIds);
586}
Derek Lamberti03614f62018-10-02 15:52:46 +0100587
Kevin Mayd92a6e42021-02-04 10:27:41 +0000588Status RuntimeImpl::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100589 const InputTensors& inputTensors,
590 const OutputTensors& outputTensors)
telsoa014fcda012018-03-09 14:13:49 +0000591{
Jan Eilers17d34da2021-12-08 16:15:12 +0000592 const auto startTime = armnn::GetTimeNow();
593
surmeh013537c2c2018-05-18 16:31:43 +0100594 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100595
596 if (!loadedNetwork)
597 {
598 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.\n";
599 return Status::Failure;
600 }
601 if (loadedNetwork->IsAsyncEnabled())
602 {
603 ARMNN_LOG(error) << "Network " << networkId << " is async enabled.\n";
604 return Status::Failure;
605 }
Narumol Prangnawarat5b4d0d52020-06-23 11:45:56 +0100606 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
607
608 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "EnqueueWorkload");
Derek Lamberti03614f62018-10-02 15:52:46 +0100609
610 static thread_local NetworkId lastId = networkId;
611 if (lastId != networkId)
612 {
613 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
614 {
615 network->FreeWorkingMemory();
616 });
617 }
618 lastId=networkId;
619
Jan Eilers17d34da2021-12-08 16:15:12 +0000620 auto status = loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
621
622 ARMNN_LOG(info) << "Execution time: " << std::setprecision(2)
623 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms\n";
624
625 return status;
telsoa014fcda012018-03-09 14:13:49 +0000626}
627
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100628Status RuntimeImpl::Execute(IWorkingMemHandle& iWorkingMemHandle,
629 const InputTensors& inputTensors,
Finn Williamsf37b9702021-09-01 18:06:04 +0100630 const OutputTensors& outputTensors,
Finn Williams8636bc72021-10-02 15:06:39 +0100631 std::vector<ImportedInputId> preImportedInputs,
632 std::vector<ImportedOutputId> preImportedOutputs)
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100633{
Jan Eilers17d34da2021-12-08 16:15:12 +0000634 const auto startTime = armnn::GetTimeNow();
635
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100636 NetworkId networkId = iWorkingMemHandle.GetNetworkId();
637 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
638
639 if (!loadedNetwork)
640 {
641 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.\n";
642 return Status::Failure;
643 }
644 if (!loadedNetwork->IsAsyncEnabled())
645 {
Keith Davise813d672021-04-22 10:10:34 +0100646 ARMNN_LOG(error) << "Attempting execute " << networkId << " when it is not async enabled.\n";
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100647 return Status::Failure;
648 }
649 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
650
651 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "Execute");
652
Jan Eilers17d34da2021-12-08 16:15:12 +0000653 auto status = loadedNetwork->Execute(inputTensors,
654 outputTensors,
655 iWorkingMemHandle,
656 preImportedInputs,
657 preImportedOutputs);
658
659 ARMNN_LOG(info) << "Execution time: " << std::setprecision(2)
660 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms\n";
661
662 return status;
Mike Kelly55a8ffd2021-04-07 20:10:49 +0100663}
664
665/// Create a new unique WorkingMemHandle object. Create multiple handles if you wish to have
666/// overlapped Execution by calling this function from different threads.
667std::unique_ptr<IWorkingMemHandle> RuntimeImpl::CreateWorkingMemHandle(NetworkId networkId)
668{
669 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
670
671 if (!loadedNetwork)
672 {
673 ARMNN_LOG(error) << "A Network with an id of " << networkId << " does not exist.\n";
674 return nullptr;
675 }
676 if (!loadedNetwork->IsAsyncEnabled())
677 {
678 ARMNN_LOG(error) << "Network " << networkId << " is not async enabled.\n";
679 return nullptr;
680 }
681 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
682
683 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "CreateWorkingMemHandle");
684
685 static thread_local NetworkId lastId = networkId;
686 if (lastId != networkId)
687 {
688 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
689 {
690 network->FreeWorkingMemory();
691 });
692 }
693 lastId=networkId;
694
695 return loadedNetwork->CreateWorkingMemHandle(networkId);
696}
697
Kevin Mayd92a6e42021-02-04 10:27:41 +0000698void RuntimeImpl::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000699{
700 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
701 loadedNetwork->RegisterDebugCallback(func);
702}
703
Kevin Mayd92a6e42021-02-04 10:27:41 +0000704void RuntimeImpl::LoadDynamicBackends(const std::string& overrideBackendPath)
Matteo Martincighe54aa062019-08-05 14:12:11 +0100705{
706 // Get the paths where to load the dynamic backends from
707 std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
708
709 // Get the shared objects to try to load as dynamic backends
710 std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
711
712 // Create a list of dynamic backends
Matteo Martincigh0c2b2892019-08-05 14:12:11 +0100713 m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
714
715 // Register the dynamic backends in the backend registry
Matteo Martincigh89533902019-08-15 12:08:06 +0100716 BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
717
718 // Add the registered dynamic backend ids to the list of supported backends
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000719 m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
telsoa014fcda012018-03-09 14:13:49 +0000720}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100721
722} // namespace armnn