blob: b1b7d51d7c4d4ac98d9327a9d03fce1967eb2b6b [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. 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>
Matthew Benthamf48afc62020-01-15 17:55:08 +00009#include <armnn/Logging.hpp>
alered01a7227ac2020-05-07 14:58:29 +010010#include <armnn/utility/Timer.hpp>
Matteo Martincighe54aa062019-08-05 14:12:11 +010011
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000012#include <armnn/backends/IBackendContext.hpp>
Matteo Martincighe54aa062019-08-05 14:12:11 +010013#include <backendsCommon/DynamicBackendUtils.hpp>
Jan Eilersbb446e52020-04-02 13:56:54 +010014#include <armnn/utility/PolymorphicDowncast.hpp>
telsoa014fcda012018-03-09 14:13:49 +000015
surmeh013537c2c2018-05-18 16:31:43 +010016#include <iostream>
17
Colm Donelan1aff3932020-02-05 17:48:59 +000018#include <backends/BackendProfiling.hpp>
telsoa014fcda012018-03-09 14:13:49 +000019
20using namespace armnn;
21using namespace std;
22
23namespace armnn
24{
25
26IRuntime* IRuntime::CreateRaw(const CreationOptions& options)
27{
28 return new Runtime(options);
29}
30
31IRuntimePtr IRuntime::Create(const CreationOptions& options)
32{
33 return IRuntimePtr(CreateRaw(options), &IRuntime::Destroy);
34}
35
36void IRuntime::Destroy(IRuntime* runtime)
37{
Jan Eilersbb446e52020-04-02 13:56:54 +010038 delete PolymorphicDowncast<Runtime*>(runtime);
telsoa014fcda012018-03-09 14:13:49 +000039}
40
41int Runtime::GenerateNetworkId()
42{
43 return m_NetworkIdCounter++;
44}
45
46Status Runtime::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr inNetwork)
47{
telsoa01c577f2c2018-08-31 09:22:23 +010048 std::string ignoredErrorMessage;
49 return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
50}
51
52Status Runtime::LoadNetwork(NetworkId& networkIdOut,
53 IOptimizedNetworkPtr inNetwork,
David Monahan4f1e8e42019-09-04 09:22:10 +010054 std::string& errorMessage)
55{
56 INetworkProperties networkProperties;
57 return LoadNetwork(networkIdOut, std::move(inNetwork), errorMessage, networkProperties);
58}
59
60Status Runtime::LoadNetwork(NetworkId& networkIdOut,
61 IOptimizedNetworkPtr inNetwork,
62 std::string& errorMessage,
63 const INetworkProperties& networkProperties)
telsoa01c577f2c2018-08-31 09:22:23 +010064{
telsoa014fcda012018-03-09 14:13:49 +000065 IOptimizedNetwork* rawNetwork = inNetwork.release();
David Beck1b61be52018-11-08 09:19:14 +000066
67 networkIdOut = GenerateNetworkId();
68
69 for (auto&& context : m_BackendContexts)
70 {
71 context.second->BeforeLoadNetwork(networkIdOut);
72 }
73
telsoa014fcda012018-03-09 14:13:49 +000074 unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
Jan Eilersbb446e52020-04-02 13:56:54 +010075 std::unique_ptr<OptimizedNetwork>(PolymorphicDowncast<OptimizedNetwork*>(rawNetwork)),
David Monahan4f1e8e42019-09-04 09:22:10 +010076 errorMessage,
Sadik Armagan3184c902020-03-18 10:57:30 +000077 networkProperties,
78 m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +000079
80 if (!loadedNetwork)
81 {
82 return Status::Failure;
83 }
84
telsoa01c577f2c2018-08-31 09:22:23 +010085 {
86 std::lock_guard<std::mutex> lockGuard(m_Mutex);
87
88 // Stores the network
89 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
90 }
telsoa014fcda012018-03-09 14:13:49 +000091
David Beck1b61be52018-11-08 09:19:14 +000092 for (auto&& context : m_BackendContexts)
93 {
94 context.second->AfterLoadNetwork(networkIdOut);
95 }
96
Sadik Armagan3184c902020-03-18 10:57:30 +000097 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +000098 {
Sadik Armagan3184c902020-03-18 10:57:30 +000099 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_LOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000100 }
101
telsoa014fcda012018-03-09 14:13:49 +0000102 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +0000103}
104
105Status Runtime::UnloadNetwork(NetworkId networkId)
106{
David Beck1b61be52018-11-08 09:19:14 +0000107 bool unloadOk = true;
108 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +0000109 {
David Beck1b61be52018-11-08 09:19:14 +0000110 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +0000111 }
David Beck1b61be52018-11-08 09:19:14 +0000112
113 if (!unloadOk)
114 {
Derek Lamberti08446972019-11-26 16:38:31 +0000115 ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): failed to unload "
116 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
David Beck1b61be52018-11-08 09:19:14 +0000117 return Status::Failure;
118 }
David Beck9efb57d2018-11-05 13:40:33 +0000119
telsoa014fcda012018-03-09 14:13:49 +0000120 {
telsoa01c577f2c2018-08-31 09:22:23 +0100121 std::lock_guard<std::mutex> lockGuard(m_Mutex);
122
123 if (m_LoadedNetworks.erase(networkId) == 0)
124 {
Derek Lamberti08446972019-11-26 16:38:31 +0000125 ARMNN_LOG(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
telsoa01c577f2c2018-08-31 09:22:23 +0100126 return Status::Failure;
127 }
Sadik Armagan3184c902020-03-18 10:57:30 +0000128
129 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000130 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000131 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_UNLOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000132 }
David Beck1b61be52018-11-08 09:19:14 +0000133 }
David Beck9efb57d2018-11-05 13:40:33 +0000134
David Beck1b61be52018-11-08 09:19:14 +0000135 for (auto&& context : m_BackendContexts)
136 {
137 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100138 }
139
Derek Lamberti08446972019-11-26 16:38:31 +0000140 ARMNN_LOG(debug) << "Runtime::UnloadNetwork(): Unloaded network with ID: " << networkId;
telsoa014fcda012018-03-09 14:13:49 +0000141 return Status::Success;
142}
143
telsoa01c577f2c2018-08-31 09:22:23 +0100144const std::shared_ptr<IProfiler> Runtime::GetProfiler(NetworkId networkId) const
145{
146 auto it = m_LoadedNetworks.find(networkId);
147 if (it != m_LoadedNetworks.end())
148 {
149 auto& loadedNetwork = it->second;
150 return loadedNetwork->GetProfiler();
151 }
152
153 return nullptr;
154}
155
Keith Davis33ed2212020-03-30 10:43:41 +0100156void Runtime::ReportStructure() // armnn::profiling::IProfilingService& profilingService as param
157{
158 // No-op for the time being, but this may be useful in future to have the profilingService available
159 // if (profilingService.IsProfilingEnabled()){}
160
161 LoadedNetworks::iterator it = m_LoadedNetworks.begin();
162 while (it != m_LoadedNetworks.end())
163 {
164 auto& loadedNetwork = it->second;
165 loadedNetwork->SendNetworkStructure();
166 // Increment the Iterator to point to next entry
167 it++;
168 }
169}
170
telsoa014fcda012018-03-09 14:13:49 +0000171Runtime::Runtime(const CreationOptions& options)
Keith Davis33ed2212020-03-30 10:43:41 +0100172 : m_NetworkIdCounter(0),
173 m_ProfilingService(*this)
telsoa014fcda012018-03-09 14:13:49 +0000174{
alered01a7227ac2020-05-07 14:58:29 +0100175 const auto start_time = armnn::GetTimeNow();
Derek Lamberti08446972019-11-26 16:38:31 +0000176 ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
David Beck1b61be52018-11-08 09:19:14 +0000177
Keith Davis33ed2212020-03-30 10:43:41 +0100178 if ( options.m_ProfilingOptions.m_TimelineEnabled && !options.m_ProfilingOptions.m_EnableProfiling )
179 {
180 throw RuntimeException("It is not possible to enable timeline reporting without profiling being enabled");
181 }
182
Matteo Martincighe54aa062019-08-05 14:12:11 +0100183 // Load any available/compatible dynamic backend before the runtime
184 // goes through the backend registry
185 LoadDynamicBackends(options.m_DynamicBackendsPath);
186
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000187 BackendIdSet supportedBackends;
David Beck1b61be52018-11-08 09:19:14 +0000188 for (const auto& id : BackendRegistryInstance().GetBackendIds())
189 {
190 // Store backend contexts for the supported ones
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000191 try {
David Beck1b61be52018-11-08 09:19:14 +0000192 auto factoryFun = BackendRegistryInstance().GetFactory(id);
193 auto backend = factoryFun();
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100194 ARMNN_ASSERT(backend.get() != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000195
196 auto context = backend->CreateBackendContext(options);
197
198 // backends are allowed to return nullptrs if they
199 // don't wish to create a backend specific context
200 if (context)
201 {
202 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
203 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000204 supportedBackends.emplace(id);
Colm Donelan1aff3932020-02-05 17:48:59 +0000205
206 unique_ptr<armnn::profiling::IBackendProfiling> profilingIface =
207 std::make_unique<armnn::profiling::BackendProfiling>(armnn::profiling::BackendProfiling(
Sadik Armagan3184c902020-03-18 10:57:30 +0000208 options, m_ProfilingService, id));
Colm Donelan1aff3932020-02-05 17:48:59 +0000209
210 // Backends may also provide a profiling context. Ask for it now.
211 auto profilingContext = backend->CreateBackendProfilingContext(options, profilingIface);
212 // Backends that don't support profiling will return a null profiling context.
213 if (profilingContext)
214 {
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100215 // Pass the context onto the profiling service.
216 m_ProfilingService.AddBackendProfilingContext(id, profilingContext);
Colm Donelan1aff3932020-02-05 17:48:59 +0000217 }
David Beck1b61be52018-11-08 09:19:14 +0000218 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000219 catch (const BackendUnavailableException&)
220 {
221 // Ignore backends which are unavailable
222 }
David Beck1b61be52018-11-08 09:19:14 +0000223 }
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100224
Finn Williams45a73622020-05-15 18:41:05 +0100225 BackendRegistryInstance().SetProfilingService(m_ProfilingService);
Finn Williamsfe5a24b2020-04-09 16:05:28 +0100226 // pass configuration info to the profiling service
227 m_ProfilingService.ConfigureProfilingService(options.m_ProfilingOptions);
228
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000229 m_DeviceSpec.AddSupportedBackends(supportedBackends);
alered01a7227ac2020-05-07 14:58:29 +0100230
231 ARMNN_LOG(info) << "Initialization time: " << std::setprecision(2)
232 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
surmeh01bceff2f2018-03-29 16:29:27 +0100233}
234
235Runtime::~Runtime()
236{
alered01a7227ac2020-05-07 14:58:29 +0100237 const auto start_time = armnn::GetTimeNow();
surmeh01bceff2f2018-03-29 16:29:27 +0100238 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100239 try
240 {
241 // Coverity fix: The following code may throw an exception of type std::length_error.
242 std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
243 std::back_inserter(networkIDs),
244 [](const auto &pair) { return pair.first; });
245 }
246 catch (const std::exception& e)
247 {
248 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
249 // exception of type std::length_error.
250 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
251 std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
252 << "\nSome of the loaded networks may not be unloaded" << std::endl;
253 }
254 // We then proceed to unload all the networks which IDs have been appended to the list
255 // up to the point the exception was thrown (if any).
surmeh01bceff2f2018-03-29 16:29:27 +0100256
257 for (auto networkID : networkIDs)
258 {
surmeh013537c2c2018-05-18 16:31:43 +0100259 try
260 {
261 // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
262 // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
263 UnloadNetwork(networkID);
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 unloading network " << networkID << ": " << e.what()
271 << std::endl;
272 }
telsoa014fcda012018-03-09 14:13:49 +0000273 }
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000274
275 // Clear all dynamic backends.
276 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
277 m_DeviceSpec.ClearDynamicBackends();
Colm Donelan1aff3932020-02-05 17:48:59 +0000278 m_BackendContexts.clear();
Finn Williams45a73622020-05-15 18:41:05 +0100279
280 BackendRegistryInstance().SetProfilingService(armnn::EmptyOptional());
alered01a7227ac2020-05-07 14:58:29 +0100281 ARMNN_LOG(info) << "Shutdown time: " << std::setprecision(2)
282 << std::fixed << armnn::GetTimeDuration(start_time).count() << " ms\n";
telsoa014fcda012018-03-09 14:13:49 +0000283}
284
surmeh013537c2c2018-05-18 16:31:43 +0100285LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
286{
287 std::lock_guard<std::mutex> lockGuard(m_Mutex);
288 return m_LoadedNetworks.at(networkId).get();
289}
290
telsoa014fcda012018-03-09 14:13:49 +0000291TensorInfo Runtime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
292{
surmeh013537c2c2018-05-18 16:31:43 +0100293 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000294}
295
296TensorInfo Runtime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
297{
surmeh013537c2c2018-05-18 16:31:43 +0100298 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000299}
300
Derek Lamberti03614f62018-10-02 15:52:46 +0100301
telsoa014fcda012018-03-09 14:13:49 +0000302Status Runtime::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100303 const InputTensors& inputTensors,
304 const OutputTensors& outputTensors)
telsoa014fcda012018-03-09 14:13:49 +0000305{
surmeh013537c2c2018-05-18 16:31:43 +0100306 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Derek Lamberti03614f62018-10-02 15:52:46 +0100307
308 static thread_local NetworkId lastId = networkId;
309 if (lastId != networkId)
310 {
311 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
312 {
313 network->FreeWorkingMemory();
314 });
315 }
316 lastId=networkId;
317
surmeh013537c2c2018-05-18 16:31:43 +0100318 return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
telsoa014fcda012018-03-09 14:13:49 +0000319}
320
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000321void Runtime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
322{
323 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
324 loadedNetwork->RegisterDebugCallback(func);
325}
326
Matteo Martincighe54aa062019-08-05 14:12:11 +0100327void Runtime::LoadDynamicBackends(const std::string& overrideBackendPath)
328{
329 // Get the paths where to load the dynamic backends from
330 std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
331
332 // Get the shared objects to try to load as dynamic backends
333 std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
334
335 // Create a list of dynamic backends
Matteo Martincigh0c2b2892019-08-05 14:12:11 +0100336 m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
337
338 // Register the dynamic backends in the backend registry
Matteo Martincigh89533902019-08-15 12:08:06 +0100339 BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
340
341 // Add the registered dynamic backend ids to the list of supported backends
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000342 m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
telsoa014fcda012018-03-09 14:13:49 +0000343}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100344
345} // namespace armnn