blob: aeecbfedc165264ebddcc5f07c3673a942064124 [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>
Jim Flynnf7713212020-07-14 09:50:59 +01009#include <LabelsAndEventClasses.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>
Jan Eilersbb446e52020-04-02 13:56:54 +010015#include <armnn/utility/PolymorphicDowncast.hpp>
telsoa014fcda012018-03-09 14:13:49 +000016
surmeh013537c2c2018-05-18 16:31:43 +010017#include <iostream>
18
Colm Donelan1aff3932020-02-05 17:48:59 +000019#include <backends/BackendProfiling.hpp>
telsoa014fcda012018-03-09 14:13:49 +000020
21using namespace armnn;
22using namespace std;
23
24namespace armnn
25{
26
27IRuntime* IRuntime::CreateRaw(const CreationOptions& options)
28{
29 return new Runtime(options);
30}
31
32IRuntimePtr IRuntime::Create(const CreationOptions& options)
33{
34 return IRuntimePtr(CreateRaw(options), &IRuntime::Destroy);
35}
36
37void IRuntime::Destroy(IRuntime* runtime)
38{
Jan Eilersbb446e52020-04-02 13:56:54 +010039 delete PolymorphicDowncast<Runtime*>(runtime);
telsoa014fcda012018-03-09 14:13:49 +000040}
41
42int Runtime::GenerateNetworkId()
43{
44 return m_NetworkIdCounter++;
45}
46
47Status Runtime::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr inNetwork)
48{
telsoa01c577f2c2018-08-31 09:22:23 +010049 std::string ignoredErrorMessage;
50 return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
51}
52
53Status Runtime::LoadNetwork(NetworkId& networkIdOut,
54 IOptimizedNetworkPtr inNetwork,
David Monahan4f1e8e42019-09-04 09:22:10 +010055 std::string& errorMessage)
56{
57 INetworkProperties networkProperties;
58 return LoadNetwork(networkIdOut, std::move(inNetwork), errorMessage, networkProperties);
59}
60
61Status Runtime::LoadNetwork(NetworkId& networkIdOut,
62 IOptimizedNetworkPtr inNetwork,
63 std::string& errorMessage,
64 const INetworkProperties& networkProperties)
telsoa01c577f2c2018-08-31 09:22:23 +010065{
telsoa014fcda012018-03-09 14:13:49 +000066 IOptimizedNetwork* rawNetwork = inNetwork.release();
David Beck1b61be52018-11-08 09:19:14 +000067
68 networkIdOut = GenerateNetworkId();
69
70 for (auto&& context : m_BackendContexts)
71 {
72 context.second->BeforeLoadNetwork(networkIdOut);
73 }
74
telsoa014fcda012018-03-09 14:13:49 +000075 unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
Jan Eilersbb446e52020-04-02 13:56:54 +010076 std::unique_ptr<OptimizedNetwork>(PolymorphicDowncast<OptimizedNetwork*>(rawNetwork)),
David Monahan4f1e8e42019-09-04 09:22:10 +010077 errorMessage,
Sadik Armagan3184c902020-03-18 10:57:30 +000078 networkProperties,
79 m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +000080
81 if (!loadedNetwork)
82 {
83 return Status::Failure;
84 }
85
telsoa01c577f2c2018-08-31 09:22:23 +010086 {
87 std::lock_guard<std::mutex> lockGuard(m_Mutex);
88
89 // Stores the network
90 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
91 }
telsoa014fcda012018-03-09 14:13:49 +000092
David Beck1b61be52018-11-08 09:19:14 +000093 for (auto&& context : m_BackendContexts)
94 {
95 context.second->AfterLoadNetwork(networkIdOut);
96 }
97
Sadik Armagan3184c902020-03-18 10:57:30 +000098 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +000099 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000100 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_LOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000101 }
102
telsoa014fcda012018-03-09 14:13:49 +0000103 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +0000104}
105
106Status Runtime::UnloadNetwork(NetworkId networkId)
107{
David Beck1b61be52018-11-08 09:19:14 +0000108 bool unloadOk = true;
109 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +0000110 {
David Beck1b61be52018-11-08 09:19:14 +0000111 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +0000112 }
David Beck1b61be52018-11-08 09:19:14 +0000113
114 if (!unloadOk)
115 {
Derek Lamberti08446972019-11-26 16:38:31 +0000116 ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): failed to unload "
117 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
David Beck1b61be52018-11-08 09:19:14 +0000118 return Status::Failure;
119 }
David Beck9efb57d2018-11-05 13:40:33 +0000120
Jim Flynnf7713212020-07-14 09:50:59 +0100121 std::unique_ptr<profiling::TimelineUtilityMethods> timelineUtils =
122 profiling::TimelineUtilityMethods::GetTimelineUtils(m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +0000123 {
telsoa01c577f2c2018-08-31 09:22:23 +0100124 std::lock_guard<std::mutex> lockGuard(m_Mutex);
125
Jim Flynnf7713212020-07-14 09:50:59 +0100126 // 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,
134 profiling::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
135 }
136 }
telsoa01c577f2c2018-08-31 09:22:23 +0100137 if (m_LoadedNetworks.erase(networkId) == 0)
138 {
Derek Lamberti08446972019-11-26 16:38:31 +0000139 ARMNN_LOG(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
telsoa01c577f2c2018-08-31 09:22:23 +0100140 return Status::Failure;
141 }
Sadik Armagan3184c902020-03-18 10:57:30 +0000142
143 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000144 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000145 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_UNLOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000146 }
David Beck1b61be52018-11-08 09:19:14 +0000147 }
David Beck9efb57d2018-11-05 13:40:33 +0000148
David Beck1b61be52018-11-08 09:19:14 +0000149 for (auto&& context : m_BackendContexts)
150 {
151 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100152 }
153
Derek Lamberti08446972019-11-26 16:38:31 +0000154 ARMNN_LOG(debug) << "Runtime::UnloadNetwork(): Unloaded network with ID: " << networkId;
telsoa014fcda012018-03-09 14:13:49 +0000155 return Status::Success;
156}
157
telsoa01c577f2c2018-08-31 09:22:23 +0100158const 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
Keith Davis33ed2212020-03-30 10:43:41 +0100170void 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
telsoa014fcda012018-03-09 14:13:49 +0000185Runtime::Runtime(const CreationOptions& options)
Keith Davis33ed2212020-03-30 10:43:41 +0100186 : m_NetworkIdCounter(0),
187 m_ProfilingService(*this)
telsoa014fcda012018-03-09 14:13:49 +0000188{
alered01a7227ac2020-05-07 14:58:29 +0100189 const auto start_time = armnn::GetTimeNow();
Derek Lamberti08446972019-11-26 16:38:31 +0000190 ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
David Beck1b61be52018-11-08 09:19:14 +0000191
Keith Davis33ed2212020-03-30 10:43:41 +0100192 if ( options.m_ProfilingOptions.m_TimelineEnabled && !options.m_ProfilingOptions.m_EnableProfiling )
193 {
194 throw RuntimeException("It is not possible to enable timeline reporting without profiling being enabled");
195 }
196
Matteo Martincighe54aa062019-08-05 14:12:11 +0100197 // Load any available/compatible dynamic backend before the runtime
198 // goes through the backend registry
199 LoadDynamicBackends(options.m_DynamicBackendsPath);
200
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000201 BackendIdSet supportedBackends;
David Beck1b61be52018-11-08 09:19:14 +0000202 for (const auto& id : BackendRegistryInstance().GetBackendIds())
203 {
204 // Store backend contexts for the supported ones
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000205 try {
David Beck1b61be52018-11-08 09:19:14 +0000206 auto factoryFun = BackendRegistryInstance().GetFactory(id);
207 auto backend = factoryFun();
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100208 ARMNN_ASSERT(backend.get() != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000209
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 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000218 supportedBackends.emplace(id);
Colm Donelan1aff3932020-02-05 17:48:59 +0000219
220 unique_ptr<armnn::profiling::IBackendProfiling> profilingIface =
221 std::make_unique<armnn::profiling::BackendProfiling>(armnn::profiling::BackendProfiling(
Sadik Armagan3184c902020-03-18 10:57:30 +0000222 options, m_ProfilingService, id));
Colm Donelan1aff3932020-02-05 17:48:59 +0000223
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 {
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100229 // Pass the context onto the profiling service.
230 m_ProfilingService.AddBackendProfilingContext(id, profilingContext);
Colm Donelan1aff3932020-02-05 17:48:59 +0000231 }
David Beck1b61be52018-11-08 09:19:14 +0000232 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000233 catch (const BackendUnavailableException&)
234 {
235 // Ignore backends which are unavailable
236 }
David Beck1b61be52018-11-08 09:19:14 +0000237 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100238
Finn Williams45a73622020-05-15 18:41:05 +0100239 BackendRegistryInstance().SetProfilingService(m_ProfilingService);
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100240 // pass configuration info to the profiling service
241 m_ProfilingService.ConfigureProfilingService(options.m_ProfilingOptions);
Jim Flynn6398a982020-05-27 17:05:21 +0100242 if (options.m_ProfilingOptions.m_EnableProfiling)
243 {
244 // try to wait for the profiling service to initialise
245 m_ProfilingService.WaitForProfilingServiceActivation(3000);
246 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100247
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000248 m_DeviceSpec.AddSupportedBackends(supportedBackends);
alered01a7227ac2020-05-07 14:58:29 +0100249
250 ARMNN_LOG(info) << "Initialization time: " << std::setprecision(2)
251 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
surmeh01bceff2f2018-03-29 16:29:27 +0100252}
253
254Runtime::~Runtime()
255{
alered01a7227ac2020-05-07 14:58:29 +0100256 const auto start_time = armnn::GetTimeNow();
surmeh01bceff2f2018-03-29 16:29:27 +0100257 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100258 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).
surmeh01bceff2f2018-03-29 16:29:27 +0100275
276 for (auto networkID : networkIDs)
277 {
surmeh013537c2c2018-05-18 16:31:43 +0100278 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 }
telsoa014fcda012018-03-09 14:13:49 +0000292 }
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000293
294 // Clear all dynamic backends.
295 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
296 m_DeviceSpec.ClearDynamicBackends();
Colm Donelan1aff3932020-02-05 17:48:59 +0000297 m_BackendContexts.clear();
Finn Williams45a73622020-05-15 18:41:05 +0100298
299 BackendRegistryInstance().SetProfilingService(armnn::EmptyOptional());
alered01a7227ac2020-05-07 14:58:29 +0100300 ARMNN_LOG(info) << "Shutdown time: " << std::setprecision(2)
301 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
telsoa014fcda012018-03-09 14:13:49 +0000302}
303
surmeh013537c2c2018-05-18 16:31:43 +0100304LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
305{
306 std::lock_guard<std::mutex> lockGuard(m_Mutex);
307 return m_LoadedNetworks.at(networkId).get();
308}
309
telsoa014fcda012018-03-09 14:13:49 +0000310TensorInfo Runtime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
311{
surmeh013537c2c2018-05-18 16:31:43 +0100312 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000313}
314
315TensorInfo Runtime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
316{
surmeh013537c2c2018-05-18 16:31:43 +0100317 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000318}
319
Derek Lamberti03614f62018-10-02 15:52:46 +0100320
telsoa014fcda012018-03-09 14:13:49 +0000321Status Runtime::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100322 const InputTensors& inputTensors,
323 const OutputTensors& outputTensors)
telsoa014fcda012018-03-09 14:13:49 +0000324{
surmeh013537c2c2018-05-18 16:31:43 +0100325 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Narumol Prangnawarat5b4d0d52020-06-23 11:45:56 +0100326 ProfilerManager::GetInstance().RegisterProfiler(loadedNetwork->GetProfiler().get());
327
328 ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "EnqueueWorkload");
Derek Lamberti03614f62018-10-02 15:52:46 +0100329
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
surmeh013537c2c2018-05-18 16:31:43 +0100340 return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
telsoa014fcda012018-03-09 14:13:49 +0000341}
342
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000343void Runtime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
344{
345 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
346 loadedNetwork->RegisterDebugCallback(func);
347}
348
Matteo Martincighe54aa062019-08-05 14:12:11 +0100349void 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
Matteo Martincigh0c2b2892019-08-05 14:12:11 +0100358 m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
359
360 // Register the dynamic backends in the backend registry
Matteo Martincigh89533902019-08-15 12:08:06 +0100361 BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
362
363 // Add the registered dynamic backend ids to the list of supported backends
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000364 m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
telsoa014fcda012018-03-09 14:13:49 +0000365}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100366
367} // namespace armnn