blob: f44606c76221e389dcaedddb2856ae1fd7fb3894 [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>
Matteo Martincighe54aa062019-08-05 14:12:11 +010010
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000011#include <armnn/backends/IBackendContext.hpp>
Matteo Martincighe54aa062019-08-05 14:12:11 +010012#include <backendsCommon/DynamicBackendUtils.hpp>
telsoa014fcda012018-03-09 14:13:49 +000013
surmeh013537c2c2018-05-18 16:31:43 +010014#include <iostream>
15
telsoa014fcda012018-03-09 14:13:49 +000016#include <boost/polymorphic_cast.hpp>
Colm Donelan1aff3932020-02-05 17:48:59 +000017#include <backends/BackendProfiling.hpp>
telsoa014fcda012018-03-09 14:13:49 +000018
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,
Sadik Armagan3184c902020-03-18 10:57:30 +000076 networkProperties,
77 m_ProfilingService);
telsoa014fcda012018-03-09 14:13:49 +000078
79 if (!loadedNetwork)
80 {
81 return Status::Failure;
82 }
83
telsoa01c577f2c2018-08-31 09:22:23 +010084 {
85 std::lock_guard<std::mutex> lockGuard(m_Mutex);
86
87 // Stores the network
88 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
89 }
telsoa014fcda012018-03-09 14:13:49 +000090
David Beck1b61be52018-11-08 09:19:14 +000091 for (auto&& context : m_BackendContexts)
92 {
93 context.second->AfterLoadNetwork(networkIdOut);
94 }
95
Sadik Armagan3184c902020-03-18 10:57:30 +000096 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +000097 {
Sadik Armagan3184c902020-03-18 10:57:30 +000098 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_LOADS);
Keith Davise394bd92019-12-02 15:12:19 +000099 }
100
telsoa014fcda012018-03-09 14:13:49 +0000101 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +0000102}
103
104Status Runtime::UnloadNetwork(NetworkId networkId)
105{
David Beck1b61be52018-11-08 09:19:14 +0000106 bool unloadOk = true;
107 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +0000108 {
David Beck1b61be52018-11-08 09:19:14 +0000109 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +0000110 }
David Beck1b61be52018-11-08 09:19:14 +0000111
112 if (!unloadOk)
113 {
Derek Lamberti08446972019-11-26 16:38:31 +0000114 ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): failed to unload "
115 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
David Beck1b61be52018-11-08 09:19:14 +0000116 return Status::Failure;
117 }
David Beck9efb57d2018-11-05 13:40:33 +0000118
telsoa014fcda012018-03-09 14:13:49 +0000119 {
telsoa01c577f2c2018-08-31 09:22:23 +0100120 std::lock_guard<std::mutex> lockGuard(m_Mutex);
121
122 if (m_LoadedNetworks.erase(networkId) == 0)
123 {
Derek Lamberti08446972019-11-26 16:38:31 +0000124 ARMNN_LOG(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
telsoa01c577f2c2018-08-31 09:22:23 +0100125 return Status::Failure;
126 }
Sadik Armagan3184c902020-03-18 10:57:30 +0000127
128 if (m_ProfilingService.IsProfilingEnabled())
Keith Davise394bd92019-12-02 15:12:19 +0000129 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000130 m_ProfilingService.IncrementCounterValue(armnn::profiling::NETWORK_UNLOADS);
Keith Davise394bd92019-12-02 15:12:19 +0000131 }
David Beck1b61be52018-11-08 09:19:14 +0000132 }
David Beck9efb57d2018-11-05 13:40:33 +0000133
David Beck1b61be52018-11-08 09:19:14 +0000134 for (auto&& context : m_BackendContexts)
135 {
136 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100137 }
138
Derek Lamberti08446972019-11-26 16:38:31 +0000139 ARMNN_LOG(debug) << "Runtime::UnloadNetwork(): Unloaded network with ID: " << networkId;
telsoa014fcda012018-03-09 14:13:49 +0000140 return Status::Success;
141}
142
telsoa01c577f2c2018-08-31 09:22:23 +0100143const std::shared_ptr<IProfiler> Runtime::GetProfiler(NetworkId networkId) const
144{
145 auto it = m_LoadedNetworks.find(networkId);
146 if (it != m_LoadedNetworks.end())
147 {
148 auto& loadedNetwork = it->second;
149 return loadedNetwork->GetProfiler();
150 }
151
152 return nullptr;
153}
154
Keith Davis33ed2212020-03-30 10:43:41 +0100155void Runtime::ReportStructure() // armnn::profiling::IProfilingService& profilingService as param
156{
157 // No-op for the time being, but this may be useful in future to have the profilingService available
158 // if (profilingService.IsProfilingEnabled()){}
159
160 LoadedNetworks::iterator it = m_LoadedNetworks.begin();
161 while (it != m_LoadedNetworks.end())
162 {
163 auto& loadedNetwork = it->second;
164 loadedNetwork->SendNetworkStructure();
165 // Increment the Iterator to point to next entry
166 it++;
167 }
168}
169
telsoa014fcda012018-03-09 14:13:49 +0000170Runtime::Runtime(const CreationOptions& options)
Keith Davis33ed2212020-03-30 10:43:41 +0100171 : m_NetworkIdCounter(0),
172 m_ProfilingService(*this)
telsoa014fcda012018-03-09 14:13:49 +0000173{
Derek Lamberti08446972019-11-26 16:38:31 +0000174 ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
David Beck1b61be52018-11-08 09:19:14 +0000175
Keith Davis33ed2212020-03-30 10:43:41 +0100176 if ( options.m_ProfilingOptions.m_TimelineEnabled && !options.m_ProfilingOptions.m_EnableProfiling )
177 {
178 throw RuntimeException("It is not possible to enable timeline reporting without profiling being enabled");
179 }
180
Jim Flynnc4728ad2019-10-07 15:15:12 +0100181 // pass configuration info to the profiling service
Sadik Armagan3184c902020-03-18 10:57:30 +0000182 m_ProfilingService.ConfigureProfilingService(options.m_ProfilingOptions);
Jim Flynnc4728ad2019-10-07 15:15:12 +0100183
Matteo Martincighe54aa062019-08-05 14:12:11 +0100184 // Load any available/compatible dynamic backend before the runtime
185 // goes through the backend registry
186 LoadDynamicBackends(options.m_DynamicBackendsPath);
187
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000188 BackendIdSet supportedBackends;
David Beck1b61be52018-11-08 09:19:14 +0000189 for (const auto& id : BackendRegistryInstance().GetBackendIds())
190 {
191 // Store backend contexts for the supported ones
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000192 try {
David Beck1b61be52018-11-08 09:19:14 +0000193 auto factoryFun = BackendRegistryInstance().GetFactory(id);
194 auto backend = factoryFun();
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100195 ARMNN_ASSERT(backend.get() != nullptr);
David Beck1b61be52018-11-08 09:19:14 +0000196
197 auto context = backend->CreateBackendContext(options);
198
199 // backends are allowed to return nullptrs if they
200 // don't wish to create a backend specific context
201 if (context)
202 {
203 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
204 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000205 supportedBackends.emplace(id);
Colm Donelan1aff3932020-02-05 17:48:59 +0000206
207 unique_ptr<armnn::profiling::IBackendProfiling> profilingIface =
208 std::make_unique<armnn::profiling::BackendProfiling>(armnn::profiling::BackendProfiling(
Sadik Armagan3184c902020-03-18 10:57:30 +0000209 options, m_ProfilingService, id));
Colm Donelan1aff3932020-02-05 17:48:59 +0000210
211 // Backends may also provide a profiling context. Ask for it now.
212 auto profilingContext = backend->CreateBackendProfilingContext(options, profilingIface);
213 // Backends that don't support profiling will return a null profiling context.
214 if (profilingContext)
215 {
David Monahanb015e5d2020-02-26 10:24:03 +0000216 // Enable profiling on the backend and assert that it returns true
217 if(profilingContext->EnableProfiling(true))
218 {
219 // Pass the context onto the profiling service.
Sadik Armagan3184c902020-03-18 10:57:30 +0000220 m_ProfilingService.AddBackendProfilingContext(id, profilingContext);
David Monahanb015e5d2020-02-26 10:24:03 +0000221 }
222 else
223 {
224 throw BackendProfilingException("Unable to enable profiling on Backend Id: " + id.Get());
225 }
Colm Donelan1aff3932020-02-05 17:48:59 +0000226 }
David Beck1b61be52018-11-08 09:19:14 +0000227 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000228 catch (const BackendUnavailableException&)
229 {
230 // Ignore backends which are unavailable
231 }
232
David Beck1b61be52018-11-08 09:19:14 +0000233 }
Matthew Bentham9a61fa62020-02-04 10:03:55 +0000234 m_DeviceSpec.AddSupportedBackends(supportedBackends);
surmeh01bceff2f2018-03-29 16:29:27 +0100235}
236
237Runtime::~Runtime()
238{
239 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100240 try
241 {
242 // Coverity fix: The following code may throw an exception of type std::length_error.
243 std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
244 std::back_inserter(networkIDs),
245 [](const auto &pair) { return pair.first; });
246 }
247 catch (const std::exception& e)
248 {
249 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
250 // exception of type std::length_error.
251 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
252 std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
253 << "\nSome of the loaded networks may not be unloaded" << std::endl;
254 }
255 // We then proceed to unload all the networks which IDs have been appended to the list
256 // up to the point the exception was thrown (if any).
surmeh01bceff2f2018-03-29 16:29:27 +0100257
258 for (auto networkID : networkIDs)
259 {
surmeh013537c2c2018-05-18 16:31:43 +0100260 try
261 {
262 // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
263 // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
264 UnloadNetwork(networkID);
265 }
266 catch (const std::exception& e)
267 {
268 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
269 // exception of type std::length_error.
270 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
271 std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
272 << std::endl;
273 }
telsoa014fcda012018-03-09 14:13:49 +0000274 }
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000275
Colm Donelan1aff3932020-02-05 17:48:59 +0000276
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000277 // Clear all dynamic backends.
278 DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
279 m_DeviceSpec.ClearDynamicBackends();
Colm Donelan1aff3932020-02-05 17:48:59 +0000280 m_BackendContexts.clear();
telsoa014fcda012018-03-09 14:13:49 +0000281}
282
surmeh013537c2c2018-05-18 16:31:43 +0100283LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
284{
285 std::lock_guard<std::mutex> lockGuard(m_Mutex);
286 return m_LoadedNetworks.at(networkId).get();
287}
288
telsoa014fcda012018-03-09 14:13:49 +0000289TensorInfo Runtime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
290{
surmeh013537c2c2018-05-18 16:31:43 +0100291 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000292}
293
294TensorInfo Runtime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
295{
surmeh013537c2c2018-05-18 16:31:43 +0100296 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000297}
298
Derek Lamberti03614f62018-10-02 15:52:46 +0100299
telsoa014fcda012018-03-09 14:13:49 +0000300Status Runtime::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100301 const InputTensors& inputTensors,
302 const OutputTensors& outputTensors)
telsoa014fcda012018-03-09 14:13:49 +0000303{
surmeh013537c2c2018-05-18 16:31:43 +0100304 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Derek Lamberti03614f62018-10-02 15:52:46 +0100305
306 static thread_local NetworkId lastId = networkId;
307 if (lastId != networkId)
308 {
309 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
310 {
311 network->FreeWorkingMemory();
312 });
313 }
314 lastId=networkId;
315
surmeh013537c2c2018-05-18 16:31:43 +0100316 return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
telsoa014fcda012018-03-09 14:13:49 +0000317}
318
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000319void Runtime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
320{
321 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
322 loadedNetwork->RegisterDebugCallback(func);
323}
324
Matteo Martincighe54aa062019-08-05 14:12:11 +0100325void Runtime::LoadDynamicBackends(const std::string& overrideBackendPath)
326{
327 // Get the paths where to load the dynamic backends from
328 std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
329
330 // Get the shared objects to try to load as dynamic backends
331 std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
332
333 // Create a list of dynamic backends
Matteo Martincigh0c2b2892019-08-05 14:12:11 +0100334 m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
335
336 // Register the dynamic backends in the backend registry
Matteo Martincigh89533902019-08-15 12:08:06 +0100337 BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
338
339 // Add the registered dynamic backend ids to the list of supported backends
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +0000340 m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
telsoa014fcda012018-03-09 14:13:49 +0000341}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100342
343} // namespace armnn