blob: 3505030273cb5fd3ffb6835cf750062177fd05ec [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 Martincighe54aa062019-08-05 14:12:11 +01008
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +00009#include <backendsCommon/BackendRegistry.hpp>
David Beck1b61be52018-11-08 09:19:14 +000010#include <backendsCommon/IBackendContext.hpp>
Matteo Martincighe54aa062019-08-05 14:12:11 +010011#include <backendsCommon/DynamicBackendUtils.hpp>
12#include <backendsCommon/DynamicBackend.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/log/trivial.hpp>
17#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,
53 std::string & errorMessage)
54{
telsoa014fcda012018-03-09 14:13:49 +000055 IOptimizedNetwork* rawNetwork = inNetwork.release();
David Beck1b61be52018-11-08 09:19:14 +000056
57 networkIdOut = GenerateNetworkId();
58
59 for (auto&& context : m_BackendContexts)
60 {
61 context.second->BeforeLoadNetwork(networkIdOut);
62 }
63
telsoa014fcda012018-03-09 14:13:49 +000064 unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
65 std::unique_ptr<OptimizedNetwork>(boost::polymorphic_downcast<OptimizedNetwork*>(rawNetwork)),
telsoa01c577f2c2018-08-31 09:22:23 +010066 errorMessage);
telsoa014fcda012018-03-09 14:13:49 +000067
68 if (!loadedNetwork)
69 {
70 return Status::Failure;
71 }
72
telsoa01c577f2c2018-08-31 09:22:23 +010073 {
74 std::lock_guard<std::mutex> lockGuard(m_Mutex);
75
76 // Stores the network
77 m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
78 }
telsoa014fcda012018-03-09 14:13:49 +000079
David Beck1b61be52018-11-08 09:19:14 +000080 for (auto&& context : m_BackendContexts)
81 {
82 context.second->AfterLoadNetwork(networkIdOut);
83 }
84
telsoa014fcda012018-03-09 14:13:49 +000085 return Status::Success;
telsoa014fcda012018-03-09 14:13:49 +000086}
87
88Status Runtime::UnloadNetwork(NetworkId networkId)
89{
David Beck1b61be52018-11-08 09:19:14 +000090 bool unloadOk = true;
91 for (auto&& context : m_BackendContexts)
David Beck9efb57d2018-11-05 13:40:33 +000092 {
David Beck1b61be52018-11-08 09:19:14 +000093 unloadOk &= context.second->BeforeUnloadNetwork(networkId);
David Beck9efb57d2018-11-05 13:40:33 +000094 }
David Beck1b61be52018-11-08 09:19:14 +000095
96 if (!unloadOk)
97 {
98 BOOST_LOG_TRIVIAL(warning) << "Runtime::UnloadNetwork(): failed to unload "
99 "network with ID:" << networkId << " because BeforeUnloadNetwork failed";
100 return Status::Failure;
101 }
David Beck9efb57d2018-11-05 13:40:33 +0000102
telsoa014fcda012018-03-09 14:13:49 +0000103 {
telsoa01c577f2c2018-08-31 09:22:23 +0100104 std::lock_guard<std::mutex> lockGuard(m_Mutex);
105
106 if (m_LoadedNetworks.erase(networkId) == 0)
107 {
108 BOOST_LOG_TRIVIAL(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
109 return Status::Failure;
110 }
David Beck1b61be52018-11-08 09:19:14 +0000111 }
David Beck9efb57d2018-11-05 13:40:33 +0000112
David Beck1b61be52018-11-08 09:19:14 +0000113 for (auto&& context : m_BackendContexts)
114 {
115 context.second->AfterUnloadNetwork(networkId);
telsoa01c577f2c2018-08-31 09:22:23 +0100116 }
117
telsoa014fcda012018-03-09 14:13:49 +0000118 BOOST_LOG_TRIVIAL(debug) << "Runtime::UnloadNetwork(): Unloaded network with ID: " << networkId;
119 return Status::Success;
120}
121
telsoa01c577f2c2018-08-31 09:22:23 +0100122const std::shared_ptr<IProfiler> Runtime::GetProfiler(NetworkId networkId) const
123{
124 auto it = m_LoadedNetworks.find(networkId);
125 if (it != m_LoadedNetworks.end())
126 {
127 auto& loadedNetwork = it->second;
128 return loadedNetwork->GetProfiler();
129 }
130
131 return nullptr;
132}
133
telsoa014fcda012018-03-09 14:13:49 +0000134Runtime::Runtime(const CreationOptions& options)
David Beck1b61be52018-11-08 09:19:14 +0000135 : m_NetworkIdCounter(0)
David Beck056be3c2018-10-22 13:16:00 +0100136 , m_DeviceSpec{BackendRegistryInstance().GetBackendIds()}
telsoa014fcda012018-03-09 14:13:49 +0000137{
138 BOOST_LOG_TRIVIAL(info) << "ArmNN v" << ARMNN_VERSION << "\n";
David Beck1b61be52018-11-08 09:19:14 +0000139
Matteo Martincighe54aa062019-08-05 14:12:11 +0100140 // Load any available/compatible dynamic backend before the runtime
141 // goes through the backend registry
142 LoadDynamicBackends(options.m_DynamicBackendsPath);
143
David Beck1b61be52018-11-08 09:19:14 +0000144 for (const auto& id : BackendRegistryInstance().GetBackendIds())
145 {
146 // Store backend contexts for the supported ones
147 if (m_DeviceSpec.GetSupportedBackends().count(id) > 0)
148 {
149 auto factoryFun = BackendRegistryInstance().GetFactory(id);
150 auto backend = factoryFun();
151 BOOST_ASSERT(backend.get() != nullptr);
152
153 auto context = backend->CreateBackendContext(options);
154
155 // backends are allowed to return nullptrs if they
156 // don't wish to create a backend specific context
157 if (context)
158 {
159 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
160 }
161 }
162 }
surmeh01bceff2f2018-03-29 16:29:27 +0100163}
164
165Runtime::~Runtime()
166{
167 std::vector<int> networkIDs;
surmeh013537c2c2018-05-18 16:31:43 +0100168 try
169 {
170 // Coverity fix: The following code may throw an exception of type std::length_error.
171 std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
172 std::back_inserter(networkIDs),
173 [](const auto &pair) { return pair.first; });
174 }
175 catch (const std::exception& e)
176 {
177 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
178 // exception of type std::length_error.
179 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
180 std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
181 << "\nSome of the loaded networks may not be unloaded" << std::endl;
182 }
183 // We then proceed to unload all the networks which IDs have been appended to the list
184 // up to the point the exception was thrown (if any).
surmeh01bceff2f2018-03-29 16:29:27 +0100185
186 for (auto networkID : networkIDs)
187 {
surmeh013537c2c2018-05-18 16:31:43 +0100188 try
189 {
190 // Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
191 // boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
192 UnloadNetwork(networkID);
193 }
194 catch (const std::exception& e)
195 {
196 // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
197 // exception of type std::length_error.
198 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
199 std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
200 << std::endl;
201 }
telsoa014fcda012018-03-09 14:13:49 +0000202 }
203}
204
surmeh013537c2c2018-05-18 16:31:43 +0100205LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
206{
207 std::lock_guard<std::mutex> lockGuard(m_Mutex);
208 return m_LoadedNetworks.at(networkId).get();
209}
210
telsoa014fcda012018-03-09 14:13:49 +0000211TensorInfo Runtime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
212{
surmeh013537c2c2018-05-18 16:31:43 +0100213 return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000214}
215
216TensorInfo Runtime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
217{
surmeh013537c2c2018-05-18 16:31:43 +0100218 return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
telsoa014fcda012018-03-09 14:13:49 +0000219}
220
Derek Lamberti03614f62018-10-02 15:52:46 +0100221
telsoa014fcda012018-03-09 14:13:49 +0000222Status Runtime::EnqueueWorkload(NetworkId networkId,
telsoa01c577f2c2018-08-31 09:22:23 +0100223 const InputTensors& inputTensors,
224 const OutputTensors& outputTensors)
telsoa014fcda012018-03-09 14:13:49 +0000225{
surmeh013537c2c2018-05-18 16:31:43 +0100226 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
Derek Lamberti03614f62018-10-02 15:52:46 +0100227
228 static thread_local NetworkId lastId = networkId;
229 if (lastId != networkId)
230 {
231 LoadedNetworkFuncSafe(lastId, [](LoadedNetwork* network)
232 {
233 network->FreeWorkingMemory();
234 });
235 }
236 lastId=networkId;
237
surmeh013537c2c2018-05-18 16:31:43 +0100238 return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
telsoa014fcda012018-03-09 14:13:49 +0000239}
240
Nattapat Chaimanowong6e948202019-03-22 14:01:46 +0000241void Runtime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func)
242{
243 LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
244 loadedNetwork->RegisterDebugCallback(func);
245}
246
Matteo Martincighe54aa062019-08-05 14:12:11 +0100247void Runtime::LoadDynamicBackends(const std::string& overrideBackendPath)
248{
249 // Get the paths where to load the dynamic backends from
250 std::vector<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
251
252 // Get the shared objects to try to load as dynamic backends
253 std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
254
255 // Create a list of dynamic backends
256 DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
telsoa014fcda012018-03-09 14:13:49 +0000257}
Matteo Martincighe54aa062019-08-05 14:12:11 +0100258
259} // namespace armnn