blob: 1cc926242082ee853e75201d71590a3653f3c4fc [file] [log] [blame]
Keith Davis02356de2019-08-26 18:28:17 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "ProfilingService.hpp"
7
Matteo Martincigha84edee2019-10-02 12:50:57 +01008#include <boost/log/trivial.hpp>
9#include <boost/format.hpp>
10
Keith Davis02356de2019-08-26 18:28:17 +010011namespace armnn
12{
13
14namespace profiling
15{
16
Matteo Martincigha84edee2019-10-02 12:50:57 +010017void ProfilingService::ResetExternalProfilingOptions(const ExternalProfilingOptions& options,
18 bool resetProfilingService)
Keith Davis02356de2019-08-26 18:28:17 +010019{
Matteo Martincigha84edee2019-10-02 12:50:57 +010020 // Update the profiling options
21 m_Options = options;
Keith Davis02356de2019-08-26 18:28:17 +010022
Matteo Martincigh54fb9572019-10-02 12:50:57 +010023 // Check if the profiling service needs to be reset
Matteo Martincigha84edee2019-10-02 12:50:57 +010024 if (resetProfilingService)
Keith Davis02356de2019-08-26 18:28:17 +010025 {
Matteo Martincigha84edee2019-10-02 12:50:57 +010026 // Reset the profiling service
Matteo Martincigh54fb9572019-10-02 12:50:57 +010027 Reset();
Keith Davis02356de2019-08-26 18:28:17 +010028 }
29}
30
Jim Flynn672d06e2019-10-15 10:18:11 +010031ProfilingState ProfilingService::ConfigureProfilingService(
32 const ExternalProfilingOptions& options,
33 bool resetProfilingService)
34{
35 ResetExternalProfilingOptions(options, resetProfilingService);
36 ProfilingState currentState = m_StateMachine.GetCurrentState();
37 if (options.m_EnableProfiling)
38 {
39 switch (currentState)
40 {
41 case ProfilingState::Uninitialised:
42 Update(); // should transition to NotConnected
43 Update(); // will either stay in NotConnected because there is no server
44 // or will enter WaitingForAck.
45 currentState = m_StateMachine.GetCurrentState();
46 if (currentState == ProfilingState::WaitingForAck)
47 {
48 Update(); // poke it again to send out the metadata packet
49 }
50 currentState = m_StateMachine.GetCurrentState();
51 return currentState;
52 case ProfilingState::NotConnected:
53 Update(); // will either stay in NotConnected because there is no server
54 // or will enter WaitingForAck
55 currentState = m_StateMachine.GetCurrentState();
56 if (currentState == ProfilingState::WaitingForAck)
57 {
58 Update(); // poke it again to send out the metadata packet
59 }
60 currentState = m_StateMachine.GetCurrentState();
61 return currentState;
62 default:
63 return currentState;
64 }
65 }
66 else
67 {
68 // Make sure profiling is shutdown
69 switch (currentState)
70 {
71 case ProfilingState::Uninitialised:
72 case ProfilingState::NotConnected:
73 return currentState;
74 default:
75 Stop();
76 return m_StateMachine.GetCurrentState();
77 }
78 }
79}
80
Matteo Martincigh54fb9572019-10-02 12:50:57 +010081void ProfilingService::Update()
Keith Davis02356de2019-08-26 18:28:17 +010082{
Matteo Martincigh54fb9572019-10-02 12:50:57 +010083 if (!m_Options.m_EnableProfiling)
Matteo Martincigha84edee2019-10-02 12:50:57 +010084 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010085 // Don't run if profiling is disabled
86 return;
Matteo Martincigha84edee2019-10-02 12:50:57 +010087 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +010088
89 ProfilingState currentState = m_StateMachine.GetCurrentState();
90 switch (currentState)
Keith Davis02356de2019-08-26 18:28:17 +010091 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010092 case ProfilingState::Uninitialised:
93 // Initialize the profiling service
94 Initialize();
95
96 // Move to the next state
97 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
98 break;
99 case ProfilingState::NotConnected:
Matteo Martincighd0613b52019-10-09 16:47:04 +0100100 // Stop the command thread (if running)
101 m_CommandHandler.Stop();
102
103 // Stop the send thread (if running)
104 m_SendCounterPacket.Stop(false);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100105
Matteo Martincighe8485382019-10-10 14:08:21 +0100106 // Stop the periodic counter capture thread (if running)
107 m_PeriodicCounterCapture.Stop();
108
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100109 // Reset any existing profiling connection
110 m_ProfilingConnection.reset();
111
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100112 try
Keith Davis02356de2019-08-26 18:28:17 +0100113 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100114 // Setup the profiling connection
Matteo Martincighd0613b52019-10-09 16:47:04 +0100115 BOOST_ASSERT(m_ProfilingConnectionFactory);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100116 m_ProfilingConnection = m_ProfilingConnectionFactory->GetProfilingConnection(m_Options);
Keith Davis02356de2019-08-26 18:28:17 +0100117 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100118 catch (const Exception& e)
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100119 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100120 BOOST_LOG_TRIVIAL(warning) << "An error has occurred when creating the profiling connection: "
Matteo Martincighd0613b52019-10-09 16:47:04 +0100121 << e.what() << std::endl;
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100122 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100123
124 // Move to the next state
125 m_StateMachine.TransitionToState(m_ProfilingConnection
126 ? ProfilingState::WaitingForAck // Profiling connection obtained, wait for ack
127 : ProfilingState::NotConnected); // Profiling connection failed, stay in the
128 // "NotConnected" state
129 break;
130 case ProfilingState::WaitingForAck:
131 BOOST_ASSERT(m_ProfilingConnection);
132
133 // Start the command thread
134 m_CommandHandler.Start(*m_ProfilingConnection);
135
136 // Start the send thread, while in "WaitingForAck" state it'll send out a "Stream MetaData" packet waiting for
137 // a valid "Connection Acknowledged" packet confirming the connection
138 m_SendCounterPacket.Start(*m_ProfilingConnection);
139
140 // The connection acknowledged command handler will automatically transition the state to "Active" once a
141 // valid "Connection Acknowledged" packet has been received
142
143 break;
144 case ProfilingState::Active:
145
Matteo Martincighe8485382019-10-10 14:08:21 +0100146 // The period counter capture thread is started by the Periodic Counter Selection command handler upon
147 // request by an external profiling service
148
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100149 break;
150 default:
151 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
152 % static_cast<int>(currentState)));
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100153 }
Keith Davis02356de2019-08-26 18:28:17 +0100154}
155
Jim Flynn53e46992019-10-14 12:31:10 +0100156void ProfilingService::Disconnect()
157{
158 ProfilingState currentState = m_StateMachine.GetCurrentState();
159 switch (currentState)
160 {
161 case ProfilingState::Uninitialised:
162 case ProfilingState::NotConnected:
163 case ProfilingState::WaitingForAck:
164 return; // NOP
165 case ProfilingState::Active:
166 // Stop the command thread (if running)
167 Stop();
168
169 break;
170 default:
171 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
172 % static_cast<int>(currentState)));
173 }
174}
175
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100176const ICounterDirectory& ProfilingService::GetCounterDirectory() const
177{
178 return m_CounterDirectory;
179}
180
Matteo Martincigha84edee2019-10-02 12:50:57 +0100181ProfilingState ProfilingService::GetCurrentState() const
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100182{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100183 return m_StateMachine.GetCurrentState();
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100184}
185
186uint16_t ProfilingService::GetCounterCount() const
187{
188 return m_CounterDirectory.GetCounterCount();
189}
190
Matteo Martincighe8485382019-10-10 14:08:21 +0100191bool ProfilingService::IsCounterRegistered(uint16_t counterUid) const
192{
193 return counterUid < m_CounterIndex.size();
194}
195
Matteo Martincigha84edee2019-10-02 12:50:57 +0100196uint32_t ProfilingService::GetCounterValue(uint16_t counterUid) const
Keith Davis02356de2019-08-26 18:28:17 +0100197{
Matteo Martincighe8485382019-10-10 14:08:21 +0100198 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100199 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
200 BOOST_ASSERT(counterValuePtr);
201 return counterValuePtr->load(std::memory_order::memory_order_relaxed);
Keith Davis02356de2019-08-26 18:28:17 +0100202}
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100203
Matteo Martincigha84edee2019-10-02 12:50:57 +0100204void ProfilingService::SetCounterValue(uint16_t counterUid, uint32_t value)
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100205{
Matteo Martincighe8485382019-10-10 14:08:21 +0100206 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100207 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
208 BOOST_ASSERT(counterValuePtr);
209 counterValuePtr->store(value, std::memory_order::memory_order_relaxed);
210}
211
212uint32_t ProfilingService::AddCounterValue(uint16_t counterUid, uint32_t value)
213{
Matteo Martincighe8485382019-10-10 14:08:21 +0100214 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100215 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
216 BOOST_ASSERT(counterValuePtr);
217 return counterValuePtr->fetch_add(value, std::memory_order::memory_order_relaxed);
218}
219
220uint32_t ProfilingService::SubtractCounterValue(uint16_t counterUid, uint32_t value)
221{
Matteo Martincighe8485382019-10-10 14:08:21 +0100222 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100223 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
224 BOOST_ASSERT(counterValuePtr);
225 return counterValuePtr->fetch_sub(value, std::memory_order::memory_order_relaxed);
226}
227
228uint32_t ProfilingService::IncrementCounterValue(uint16_t counterUid)
229{
Matteo Martincighe8485382019-10-10 14:08:21 +0100230 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100231 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
232 BOOST_ASSERT(counterValuePtr);
233 return counterValuePtr->operator++(std::memory_order::memory_order_relaxed);
234}
235
236uint32_t ProfilingService::DecrementCounterValue(uint16_t counterUid)
237{
Matteo Martincighe8485382019-10-10 14:08:21 +0100238 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100239 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
240 BOOST_ASSERT(counterValuePtr);
241 return counterValuePtr->operator--(std::memory_order::memory_order_relaxed);
242}
243
244void ProfilingService::Initialize()
245{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100246 // Register a category for the basic runtime counters
247 if (!m_CounterDirectory.IsCategoryRegistered("ArmNN_Runtime"))
248 {
249 m_CounterDirectory.RegisterCategory("ArmNN_Runtime");
250 }
251
252 // Register a counter for the number of loaded networks
253 if (!m_CounterDirectory.IsCounterRegistered("Loaded networks"))
254 {
255 const Counter* loadedNetworksCounter =
256 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
257 0,
258 0,
259 1.f,
260 "Loaded networks",
261 "The number of networks loaded at runtime",
262 std::string("networks"));
263 BOOST_ASSERT(loadedNetworksCounter);
264 InitializeCounterValue(loadedNetworksCounter->m_Uid);
265 }
266
267 // Register a counter for the number of registered backends
268 if (!m_CounterDirectory.IsCounterRegistered("Registered backends"))
269 {
270 const Counter* registeredBackendsCounter =
271 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
272 0,
273 0,
274 1.f,
275 "Registered backends",
276 "The number of registered backends",
277 std::string("backends"));
278 BOOST_ASSERT(registeredBackendsCounter);
279 InitializeCounterValue(registeredBackendsCounter->m_Uid);
280 }
281
282 // Register a counter for the number of inferences run
283 if (!m_CounterDirectory.IsCounterRegistered("Inferences run"))
284 {
285 const Counter* inferencesRunCounter =
286 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
287 0,
288 0,
289 1.f,
290 "Inferences run",
291 "The number of inferences run",
292 std::string("inferences"));
293 BOOST_ASSERT(inferencesRunCounter);
294 InitializeCounterValue(inferencesRunCounter->m_Uid);
295 }
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100296}
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100297
Matteo Martincigha84edee2019-10-02 12:50:57 +0100298void ProfilingService::InitializeCounterValue(uint16_t counterUid)
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100299{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100300 // Increase the size of the counter index if necessary
301 if (counterUid >= m_CounterIndex.size())
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100302 {
Matteo Martincigha84edee2019-10-02 12:50:57 +0100303 m_CounterIndex.resize(boost::numeric_cast<size_t>(counterUid) + 1);
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100304 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100305
306 // Create a new atomic counter and add it to the list
307 m_CounterValues.emplace_back(0);
308
309 // Register the new counter to the counter index for quick access
310 std::atomic<uint32_t>* counterValuePtr = &(m_CounterValues.back());
311 m_CounterIndex.at(counterUid) = counterValuePtr;
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100312}
313
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100314void ProfilingService::Reset()
315{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100316 // Stop the profiling service...
Jim Flynn53e46992019-10-14 12:31:10 +0100317 Stop();
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100318
Jim Flynn53e46992019-10-14 12:31:10 +0100319 // ...then delete all the counter data and configuration...
320 m_CounterIndex.clear();
321 m_CounterValues.clear();
322 m_CounterDirectory.Clear();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100323
Jim Flynn53e46992019-10-14 12:31:10 +0100324 // ...finally reset the profiling state machine
325 m_StateMachine.Reset();
326}
327
328void ProfilingService::Stop()
329{
Matteo Martincighd0613b52019-10-09 16:47:04 +0100330 // The order in which we reset/stop the components is not trivial!
331
332 // First stop the threads (Command Handler first)...
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100333 m_CommandHandler.Stop();
334 m_SendCounterPacket.Stop(false);
Matteo Martincighe8485382019-10-10 14:08:21 +0100335 m_PeriodicCounterCapture.Stop();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100336
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100337 // ...then close and destroy the profiling connection...
Jim Flynn53e46992019-10-14 12:31:10 +0100338 if (m_ProfilingConnection != nullptr && m_ProfilingConnection->IsOpen())
339 {
340 m_ProfilingConnection->Close();
341 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100342 m_ProfilingConnection.reset();
343
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100344 // ...then move to the "NotConnected" state
Jim Flynn53e46992019-10-14 12:31:10 +0100345 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100346}
347
Matteo Martincighe8485382019-10-10 14:08:21 +0100348inline void ProfilingService::CheckCounterUid(uint16_t counterUid) const
349{
350 if (!IsCounterRegistered(counterUid))
351 {
352 throw InvalidArgumentException(boost::str(boost::format("Counter UID %1% is not registered") % counterUid));
353 }
354}
355
Keith Davis02356de2019-08-26 18:28:17 +0100356} // namespace profiling
357
Matteo Martincigha84edee2019-10-02 12:50:57 +0100358} // namespace armnn