ArmNN
 20.08
Runtime.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #include "Runtime.hpp"
6 
7 #include <armnn/Version.hpp>
10 #include <armnn/Logging.hpp>
11 #include <armnn/utility/Timer.hpp>
12 
16 
17 #include <iostream>
18 
20 
21 using namespace armnn;
22 using namespace std;
23 
24 namespace armnn
25 {
26 
28 {
29  return new Runtime(options);
30 }
31 
33 {
34  return IRuntimePtr(CreateRaw(options), &IRuntime::Destroy);
35 }
36 
38 {
39  delete PolymorphicDowncast<Runtime*>(runtime);
40 }
41 
42 int Runtime::GenerateNetworkId()
43 {
44  return m_NetworkIdCounter++;
45 }
46 
48 {
49  std::string ignoredErrorMessage;
50  return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
51 }
52 
54  IOptimizedNetworkPtr inNetwork,
55  std::string& errorMessage)
56 {
57  INetworkProperties networkProperties;
58  return LoadNetwork(networkIdOut, std::move(inNetwork), errorMessage, networkProperties);
59 }
60 
62  IOptimizedNetworkPtr inNetwork,
63  std::string& errorMessage,
64  const INetworkProperties& networkProperties)
65 {
66  IOptimizedNetwork* rawNetwork = inNetwork.release();
67 
68  networkIdOut = GenerateNetworkId();
69 
70  for (auto&& context : m_BackendContexts)
71  {
72  context.second->BeforeLoadNetwork(networkIdOut);
73  }
74 
75  unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
76  std::unique_ptr<OptimizedNetwork>(PolymorphicDowncast<OptimizedNetwork*>(rawNetwork)),
77  errorMessage,
78  networkProperties,
79  m_ProfilingService);
80 
81  if (!loadedNetwork)
82  {
83  return Status::Failure;
84  }
85 
86  {
87  std::lock_guard<std::mutex> lockGuard(m_Mutex);
88 
89  // Stores the network
90  m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
91  }
92 
93  for (auto&& context : m_BackendContexts)
94  {
95  context.second->AfterLoadNetwork(networkIdOut);
96  }
97 
98  if (m_ProfilingService.IsProfilingEnabled())
99  {
100  m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_LOADS);
101  }
102 
103  return Status::Success;
104 }
105 
107 {
108  bool unloadOk = true;
109  for (auto&& context : m_BackendContexts)
110  {
111  unloadOk &= context.second->BeforeUnloadNetwork(networkId);
112  }
113 
114  if (!unloadOk)
115  {
116  ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): failed to unload "
117  "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
118  return Status::Failure;
119  }
120 
121  std::unique_ptr<profiling::TimelineUtilityMethods> timelineUtils =
123  {
124  std::lock_guard<std::mutex> lockGuard(m_Mutex);
125 
126  // If timeline recording is on mark the Network end of life
127  if (timelineUtils)
128  {
129  auto search = m_LoadedNetworks.find(networkId);
130  if (search != m_LoadedNetworks.end())
131  {
132  profiling::ProfilingGuid networkGuid = search->second->GetNetworkGuid();
133  timelineUtils->RecordEvent(networkGuid,
135  }
136  }
137  if (m_LoadedNetworks.erase(networkId) == 0)
138  {
139  ARMNN_LOG(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
140  return Status::Failure;
141  }
142 
143  if (m_ProfilingService.IsProfilingEnabled())
144  {
145  m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_UNLOADS);
146  }
147  }
148 
149  for (auto&& context : m_BackendContexts)
150  {
151  context.second->AfterUnloadNetwork(networkId);
152  }
153 
154  ARMNN_LOG(debug) << "Runtime::UnloadNetwork(): Unloaded network with ID: " << networkId;
155  return Status::Success;
156 }
157 
158 const std::shared_ptr<IProfiler> Runtime::GetProfiler(NetworkId networkId) const
159 {
160  auto it = m_LoadedNetworks.find(networkId);
161  if (it != m_LoadedNetworks.end())
162  {
163  auto& loadedNetwork = it->second;
164  return loadedNetwork->GetProfiler();
165  }
166 
167  return nullptr;
168 }
169 
170 void Runtime::ReportStructure() // armnn::profiling::IProfilingService& profilingService as param
171 {
172  // No-op for the time being, but this may be useful in future to have the profilingService available
173  // if (profilingService.IsProfilingEnabled()){}
174 
175  LoadedNetworks::iterator it = m_LoadedNetworks.begin();
176  while (it != m_LoadedNetworks.end())
177  {
178  auto& loadedNetwork = it->second;
179  loadedNetwork->SendNetworkStructure();
180  // Increment the Iterator to point to next entry
181  it++;
182  }
183 }
184 
186  : m_NetworkIdCounter(0),
187  m_ProfilingService(*this)
188 {
189  const auto start_time = armnn::GetTimeNow();
190  ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
191 
193  {
194  throw RuntimeException("It is not possible to enable timeline reporting without profiling being enabled");
195  }
196 
197  // Load any available/compatible dynamic backend before the runtime
198  // goes through the backend registry
199  LoadDynamicBackends(options.m_DynamicBackendsPath);
200 
201  BackendIdSet supportedBackends;
202  for (const auto& id : BackendRegistryInstance().GetBackendIds())
203  {
204  // Store backend contexts for the supported ones
205  try {
206  auto factoryFun = BackendRegistryInstance().GetFactory(id);
207  auto backend = factoryFun();
208  ARMNN_ASSERT(backend.get() != nullptr);
209 
210  auto context = backend->CreateBackendContext(options);
211 
212  // backends are allowed to return nullptrs if they
213  // don't wish to create a backend specific context
214  if (context)
215  {
216  m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
217  }
218  supportedBackends.emplace(id);
219 
220  unique_ptr<armnn::profiling::IBackendProfiling> profilingIface =
221  std::make_unique<armnn::profiling::BackendProfiling>(armnn::profiling::BackendProfiling(
222  options, m_ProfilingService, id));
223 
224  // Backends may also provide a profiling context. Ask for it now.
225  auto profilingContext = backend->CreateBackendProfilingContext(options, profilingIface);
226  // Backends that don't support profiling will return a null profiling context.
227  if (profilingContext)
228  {
229  // Pass the context onto the profiling service.
230  m_ProfilingService.AddBackendProfilingContext(id, profilingContext);
231  }
232  }
233  catch (const BackendUnavailableException&)
234  {
235  // Ignore backends which are unavailable
236  }
237  }
238 
239  BackendRegistryInstance().SetProfilingService(m_ProfilingService);
240  // pass configuration info to the profiling service
241  m_ProfilingService.ConfigureProfilingService(options.m_ProfilingOptions);
243  {
244  // try to wait for the profiling service to initialise
245  m_ProfilingService.WaitForProfilingServiceActivation(3000);
246  }
247 
248  m_DeviceSpec.AddSupportedBackends(supportedBackends);
249 
250  ARMNN_LOG(info) << "Initialization time: " << std::setprecision(2)
251  << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
252 }
253 
255 {
256  const auto start_time = armnn::GetTimeNow();
257  std::vector<int> networkIDs;
258  try
259  {
260  // Coverity fix: The following code may throw an exception of type std::length_error.
261  std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
262  std::back_inserter(networkIDs),
263  [](const auto &pair) { return pair.first; });
264  }
265  catch (const std::exception& e)
266  {
267  // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
268  // exception of type std::length_error.
269  // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
270  std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
271  << "\nSome of the loaded networks may not be unloaded" << std::endl;
272  }
273  // We then proceed to unload all the networks which IDs have been appended to the list
274  // up to the point the exception was thrown (if any).
275 
276  for (auto networkID : networkIDs)
277  {
278  try
279  {
280  // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
281  // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
282  UnloadNetwork(networkID);
283  }
284  catch (const std::exception& e)
285  {
286  // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
287  // exception of type std::length_error.
288  // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
289  std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
290  << std::endl;
291  }
292  }
293 
294  // Clear all dynamic backends.
296  m_DeviceSpec.ClearDynamicBackends();
297  m_BackendContexts.clear();
298 
300  ARMNN_LOG(info) << "Shutdown time: " << std::setprecision(2)
301  << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
302 }
303 
304 LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
305 {
306  std::lock_guard<std::mutex> lockGuard(m_Mutex);
307  return m_LoadedNetworks.at(networkId).get();
308 }
309 
311 {
312  return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
313 }
314 
316 {
317  return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
318 }
319 
320 
322  const InputTensors& inputTensors,
323  const OutputTensors& outputTensors)
324 {
325  LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
327 
329 
330  static thread_local NetworkId lastId = networkId;
331  if (lastId != networkId)
332  {
333  LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
334  {
335  network->FreeWorkingMemory();
336  });
337  }
338  lastId=networkId;
339 
340  return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
341 }
342 
344 {
345  LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
346  loadedNetwork->RegisterDebugCallback(func);
347 }
348 
349 void Runtime::LoadDynamicBackends(const std::string& overrideBackendPath)
350 {
351  // Get the paths where to load the dynamic backends from
352  std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
353 
354  // Get the shared objects to try to load as dynamic backends
355  std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
356 
357  // Create a list of dynamic backends
358  m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
359 
360  // Register the dynamic backends in the backend registry
361  BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
362 
363  // Add the registered dynamic backend ids to the list of supported backends
364  m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
365 }
366 
367 } // namespace armnn
void AddSupportedBackends(const BackendIdSet &backendIds, bool isDynamic=false)
Definition: DeviceSpec.hpp:30
#define ARMNN_VERSION
ARMNN_VERSION: "X.Y.Z" where: X = Major version number Y = Minor version number Z = Patch version num...
Definition: Version.hpp:22
virtual TensorInfo GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const override
Definition: Runtime.cpp:315
void WaitForProfilingServiceActivation(unsigned int timeout) override
static IRuntimePtr Create(const CreationOptions &options)
Definition: Runtime.cpp:32
FactoryFunction GetFactory(const BackendId &id) const
std::chrono::duration< double, std::milli > GetTimeDuration(std::chrono::high_resolution_clock::time_point start_time)
Definition: Timer.hpp:19
static void DeregisterDynamicBackends(const BackendIdSet &dynamicBackends)
void RegisterProfiler(Profiler *profiler)
Definition: Profiling.cpp:493
std::unordered_set< BackendId > BackendIdSet
Definition: BackendId.hpp:191
static std::unique_ptr< TimelineUtilityMethods > GetTimelineUtils(ProfilingService &profilingService)
static ProfilerManager & GetInstance()
Definition: Profiling.cpp:486
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
Definition: IRuntime.hpp:25
TensorInfo GetInputTensorInfo(LayerBindingId layerId) const
#define ARMNN_LOG(severity)
Definition: Logging.hpp:163
BackendRegistry & BackendRegistryInstance()
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:324
static std::vector< DynamicBackendPtr > CreateDynamicBackends(const std::vector< std::string > &sharedObjects)
const std::shared_ptr< Profiler > & GetProfiler() const
int NetworkId
Definition: IRuntime.hpp:20
std::chrono::high_resolution_clock::time_point GetTimeNow()
Definition: Timer.hpp:14
TensorInfo GetOutputTensorInfo(LayerBindingId layerId) const
Copyright (c) 2020 ARM Limited.
std::function< void(LayerGuid guid, unsigned int slotIndex, ITensorHandle *tensorHandle)> DebugCallbackFunction
Define the type of callback for the Debug layer to call.
Definition: Types.hpp:267
virtual const std::shared_ptr< IProfiler > GetProfiler(NetworkId networkId) const override
Gets the profiler corresponding to the given network id.
Definition: Runtime.cpp:158
static std::vector< std::string > GetBackendPaths(const std::string &overrideBackendPath="")
static ARMNN_DLLEXPORT ProfilingStaticGuid ARMNN_PROFILING_EOL_EVENT_CLASS
#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name)
Definition: Profiling.hpp:169
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:194
static void Destroy(IRuntime *runtime)
Definition: Runtime.cpp:37
virtual void ReportStructure() override
Definition: Runtime.cpp:170
virtual void RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction &func) override
Registers a callback function to debug layers performing custom computations on intermediate tensors...
Definition: Runtime.cpp:343
static std::vector< std::string > GetSharedObjects(const std::vector< std::string > &backendPaths)
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:325
Status
enumeration
Definition: Types.hpp:26
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:593
void SetProfilingService(armnn::Optional< profiling::ProfilingService &> profilingService)
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
static IRuntime * CreateRaw(const CreationOptions &options)
Definition: Runtime.cpp:27
Status EnqueueWorkload(const InputTensors &inputTensors, const OutputTensors &outputTensors)
std::string m_DynamicBackendsPath
Setting this value will override the paths set by the DYNAMIC_BACKEND_PATHS compiler directive Only a...
Definition: IRuntime.hpp:59
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
Definition: Optional.hpp:32
virtual Status LoadNetwork(NetworkId &networkIdOut, IOptimizedNetworkPtr network) override
Loads a complete network into the Runtime.
Definition: Runtime.cpp:47
void RegisterDebugCallback(const DebugCallbackFunction &func)
const BackendIdSet & GetDynamicBackends() const
Definition: DeviceSpec.hpp:48
void ClearDynamicBackends()
Definition: DeviceSpec.hpp:39
virtual Status UnloadNetwork(NetworkId networkId) override
Unloads a network from the Runtime.
Definition: Runtime.cpp:106
static BackendIdSet RegisterDynamicBackends(const std::vector< DynamicBackendPtr > &dynamicBackends)
void AddBackendProfilingContext(const BackendId backendId, std::shared_ptr< armnn::profiling::IBackendProfilingContext > profilingContext)
ExternalProfilingOptions m_ProfilingOptions
Definition: IRuntime.hpp:83
Runtime(const CreationOptions &options)
Creates a runtime for workload execution.
Definition: Runtime.cpp:185
virtual Status EnqueueWorkload(NetworkId networkId, const InputTensors &inputTensors, const OutputTensors &outputTensors) override
Evaluates a network using input in inputTensors and outputs filled into outputTensors.
Definition: Runtime.cpp:321
ProfilingState ConfigureProfilingService(const ExternalProfilingOptions &options, bool resetProfilingService=false)
static std::unique_ptr< LoadedNetwork > MakeLoadedNetwork(std::unique_ptr< OptimizedNetwork > net, std::string &errorMessage, const INetworkProperties &networkProperties, profiling::ProfilingService &profilingService)
virtual TensorInfo GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const override
Definition: Runtime.cpp:310
Class for non-fatal exceptions raised while initialising a backend.
Definition: Exceptions.hpp:68