blob: 4ad6fa59a046ec56d1bf25e34c9b8f1c02db3b99 [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>
Matteo Martincighe54aa062019-08-05 14:12:11 +01009
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000010#include <armnn/backends/IBackendContext.hpp>
Matteo Martincighe54aa062019-08-05 14:12:11 +010011#include <backendsCommon/DynamicBackendUtils.hpp>
telsoa014fcda012018-03-09 14:13:49 +000012
Narumol Prangnawarat85ad78c2019-11-18 15:34:23 +000013#include <ProfilingService.hpp>
Jim Flynnc4728ad2019-10-07 15:15:12 +010014
surmeh013537c2c2018-05-18 16:31:43 +010015#include <iostream>
16
telsoa014fcda012018-03-09 14:13:49 +000017#include <boost/polymorphic_cast.hpp>
18
19using namespace armnn;
20using namespace std;
21
22namespace armnn
23{
24
25IRuntime* IRuntime::CreateRaw(const CreationOptions& options)
26{
27 return new Runtime(options);
28}
29
30IRuntimePtr IRuntime::Create(const CreationOptions& options)
31{
32 return IRuntimePtr(CreateRaw(options), &IRuntime::Destroy);
33}
34
35void IRuntime::Destroy(IRuntime* runtime)
36{
37 delete boost::polymorphic_downcast<Runtime*>(runtime);
38}
39
40int Runtime::GenerateNetworkId()
41{
42 return m_NetworkIdCounter++;
43}
44
45Status Runtime::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr inNetwork)
46{
telsoa01c577f2c2018-08-31 09:22:23 +010047 std::string ignoredErrorMessage;
48 return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
49}
50
51Status Runtime::LoadNetwork(NetworkId& networkIdOut,
52 IOptimizedNetworkPtr inNetwork,
David Monahan4f1e8e42019-09-04 09:22:10 +010053 std::string& errorMessage)
54{
55 INetworkProperties networkProperties;
56 return LoadNetwork(networkIdOut, std::move(inNetwork), errorMessage, networkProperties);
57}
58
59Status Runtime::LoadNetwork(NetworkId& networkIdOut,
60 IOptimizedNetworkPtr inNetwork,
61 std::string& errorMessage,
62 const INetworkProperties& networkProperties)
telsoa01c577f2c2018-08-31 09:22:23 +010063{
telsoa014fcda012018-03-09 14:13:49 +000064 IOptimizedNetwork* rawNetwork = inNetwork.release();
David Beck1b61be52018-11-08 09:19:14 +000065
66 networkIdOut = GenerateNetworkId();
67
68 for (auto&& context : m_BackendContexts)
69 {
70 context.second->BeforeLoadNetwork(networkIdOut);
71 }
72
telsoa014fcda012018-03-09 14:13:49 +000073 unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
74 std::unique_ptr<OptimizedNetwork>(boost::polymorphic_downcast<OptimizedNetwork*>(rawNetwork)),
David Monahan4f1e8e42019-09-04 09:22:10 +010075 errorMessage,
76 networkProperties);
telsoa014fcda012018-03-09 14:13:49 +000077
78 if (!loadedNetwork)
79 {
80 return Status::Failure;
81 }
82
telsoa01c577f2c2018-08-31 09:22:23 +010083 {
84 std::lock_guard<std::mutex> lockGuard(m_Mutex);
85
86 // Stores the network
87 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
88 }
telsoa014fcda012018-03-09 14:13:49 +000089
David Beck1b61be52018-11-08 09:19:14 +000090 for (auto&& context : m_BackendContexts)
91 {
92 context.second->AfterLoadNetwork(networkIdOut);
93 }
94
telsoa014fcda012018-03-09 14:13:49 +000095 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +000096}
97
98Status Runtime::UnloadNetwork(NetworkId networkId)
99{
David Beck1b61be52018-11-08 09:19:14 +0000100 bool unloadOk = true;
101 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +0000102 {
David Beck1b61be52018-11-08 09:19:14 +0000103 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +0000104 }
David Beck1b61be52018-11-08 09:19:14 +0000105
106 if (!unloadOk)
107 {
Derek Lamberti08446972019-11-26 16:38:31 +0000108 ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): failed to unload "
109 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
David Beck1b61be52018-11-08 09:19:14 +0000110 return Status::Failure;
111 }
David Beck9efb57d2018-11-05 13:40:33 +0000112
telsoa014fcda012018-03-09 14:13:49 +0000113 {
telsoa01c577f2c2018-08-31 09:22:23 +0100114 std::lock_guard<std::mutex> lockGuard(m_Mutex);
115
116 if (m_LoadedNetworks.erase(networkId) == 0)
117 {
Derek Lamberti08446972019-11-26 16:38:31 +0000118 ARMNN_LOG(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
telsoa01c577f2c2018-08-31 09:22:23 +0100119 return Status::Failure;
120 }
David Beck1b61be52018-11-08 09:19:14 +0000121 }
David Beck9efb57d2018-11-05 13:40:33 +0000122
David Beck1b61be52018-11-08 09:19:14 +0000123 for (auto&& context : m_BackendContexts)
124 {
125 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100126 }
127
Derek Lamberti08446972019-11-26 16:38:31 +0000128 ARMNN_LOG(debug) << "Runtime::UnloadNetwork(): Unloaded network with ID: " << networkId;
telsoa014fcda012018-03-09 14:13:49 +0000129 return Status::Success;
130}
131
telsoa01c577f2c2018-08-31 09:22:23 +0100132const std::shared_ptr<IProfiler> Runtime::GetProfiler(NetworkId networkId) const
133{
134 auto it = m_LoadedNetworks.find(networkId);
135 if (it != m_LoadedNetworks.end())
136 {
137 auto& loadedNetwork = it->second;
138 return loadedNetwork->GetProfiler();
139 }
140
141 return nullptr;
142}
143
telsoa014fcda012018-03-09 14:13:49 +0000144Runtime::Runtime(const CreationOptions& options)
David Beck1b61be52018-11-08 09:19:14 +0000145 : m_NetworkIdCounter(0)
David Beck056be3c2018-10-22 13:16:00 +0100146 , m_DeviceSpec{BackendRegistryInstance().GetBackendIds()}
telsoa014fcda012018-03-09 14:13:49 +0000147{
Derek Lamberti08446972019-11-26 16:38:31 +0000148 ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
David Beck1b61be52018-11-08 09:19:14 +0000149
Jim Flynnc4728ad2019-10-07 15:15:12 +0100150 // pass configuration info to the profiling service
Jim Flynn672d06e2019-10-15 10:18:11 +0100151 armnn::profiling::ProfilingService::Instance().ConfigureProfilingService(options.m_ProfilingOptions);
Jim Flynnc4728ad2019-10-07 15:15:12 +0100152
Matteo Martincighe54aa062019-08-05 14:12:11 +0100153 // Load any available/compatible dynamic backend before the runtime
154 // goes through the backend registry
155 LoadDynamicBackends(options.m_DynamicBackendsPath);
156
David Beck1b61be52018-11-08 09:19:14 +0000157 for (const auto& id : BackendRegistryInstance().GetBackendIds())
158 {
159 // Store backend contexts for the supported ones
Matteo Martincigh3d8a9ed2019-08-08 10:49:03 +0100160 const BackendIdSet& supportedBackends = m_DeviceSpec.GetSupportedBackends();
Matteo Martincigh89533902019-08-15 12:08:06 +0100161 if (supportedBackends.find(id) != supportedBackends.end())
David Beck1b61be52018-11-08 09:19:14 +0000162 {
163 auto factoryFun = BackendRegistryInstance().GetFactory(id);
164 auto backend = factoryFun();
165 BOOST_ASSERT(backend.get() != nullptr);
166
167 auto context = backend->CreateBackendContext(options);
168
169 // backends are allowed to return nullptrs if they
170 // don't wish to create a backend specific context
171 if (context)
172 {
173 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
174 }
175 }
176 }
surmeh01bceff2f2018-03-29 16:29:27 +0100177}
178
179Runtime::~Runtime()
180{
181 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100182 try
183 {
184 // Coverity fix: The following code may throw an exception of type std::length_error.
185 std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
186 std::back_inserter(networkIDs),
187 [](const auto &pair) { return pair.first; });
188 }
189 catch (const std::exception& e)
190 {
191 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
192 // exception of type std::length_error.
193 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
194 std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
195 << "\nSome of the loaded networks may not be unloaded" << std::endl;
196 }
197 // We then proceed to unload all the networks which IDs have been appended to the list
198 // up to the point the exception was thrown (if any).
surmeh01bceff2f2018-03-29 16:29:27 +0100199
200 for (auto networkID : networkIDs)
201 {
surmeh013537c2c2018-05-18 16:31:43 +0100202 try
203 {
204 // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
205 // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
206 UnloadNetwork(networkID);
207 }
208 catch (const std::exception& e)
209 {
210 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
211 // exception of type std::length_error.
212 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
213 std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
214 << std::endl;
215 }
telsoa014fcda012018-03-09 14:13:49 +0000216 }
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000217
218 // Clear all dynamic backends.
219 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
220 m_DeviceSpec.ClearDynamicBackends();
telsoa014fcda012018-03-09 14:13:49 +0000221}
222
surmeh013537c2c2018-05-18 16:31:43 +0100223LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
224{
225 std::lock_guard<std::mutex> lockGuard(m_Mutex);
226 return m_LoadedNetworks.at(networkId).get();
227}
228
telsoa014fcda012018-03-09 14:13:49 +0000229TensorInfo Runtime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
230{
surmeh013537c2c2018-05-18 16:31:43 +0100231 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000232}
233
234TensorInfo Runtime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
235{
surmeh013537c2c2018-05-18 16:31:43 +0100236 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000237}
238
Derek Lamberti03614f62018-10-02 15:52:46 +0100239
telsoa014fcda012018-03-09 14:13:49 +0000240Status Runtime::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100241 const InputTensors& inputTensors,
242 const OutputTensors& outputTensors)
telsoa014fcda012018-03-09 14:13:49 +0000243{
surmeh013537c2c2018-05-18 16:31:43 +0100244 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Derek Lamberti03614f62018-10-02 15:52:46 +0100245
246 static thread_local NetworkId lastId = networkId;
247 if (lastId != networkId)
248 {
249 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
250 {
251 network->FreeWorkingMemory();
252 });
253 }
254 lastId=networkId;
255
surmeh013537c2c2018-05-18 16:31:43 +0100256 return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
telsoa014fcda012018-03-09 14:13:49 +0000257}
258
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000259void Runtime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
260{
261 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
262 loadedNetwork->RegisterDebugCallback(func);
263}
264
Matteo Martincighe54aa062019-08-05 14:12:11 +0100265void Runtime::LoadDynamicBackends(const std::string& overrideBackendPath)
266{
267 // Get the paths where to load the dynamic backends from
268 std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
269
270 // Get the shared objects to try to load as dynamic backends
271 std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
272
273 // Create a list of dynamic backends
Matteo Martincigh0c2b2892019-08-05 14:12:11 +0100274 m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
275
276 // Register the dynamic backends in the backend registry
Matteo Martincigh89533902019-08-15 12:08:06 +0100277 BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
278
279 // Add the registered dynamic backend ids to the list of supported backends
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000280 m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
telsoa014fcda012018-03-09 14:13:49 +0000281}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100282
283} // namespace armnn