blob: 6122ed99c20d6007e5d29c5e48be4677e71f50ba [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
Jim Flynn00f3aaf2019-10-24 11:58:06 +0100244ProfilingDynamicGuid ProfilingService::NextGuid()
245{
246 return m_GuidGenerator.NextGuid();
247}
248
249ProfilingStaticGuid ProfilingService::GenerateStaticId(const std::string& str)
250{
251 return m_GuidGenerator.GenerateStaticId(str);
252}
253
Matteo Martincigha84edee2019-10-02 12:50:57 +0100254void ProfilingService::Initialize()
255{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100256 // Register a category for the basic runtime counters
257 if (!m_CounterDirectory.IsCategoryRegistered("ArmNN_Runtime"))
258 {
259 m_CounterDirectory.RegisterCategory("ArmNN_Runtime");
260 }
261
262 // Register a counter for the number of loaded networks
263 if (!m_CounterDirectory.IsCounterRegistered("Loaded networks"))
264 {
265 const Counter* loadedNetworksCounter =
266 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
267 0,
268 0,
269 1.f,
270 "Loaded networks",
271 "The number of networks loaded at runtime",
272 std::string("networks"));
273 BOOST_ASSERT(loadedNetworksCounter);
274 InitializeCounterValue(loadedNetworksCounter->m_Uid);
275 }
276
277 // Register a counter for the number of registered backends
278 if (!m_CounterDirectory.IsCounterRegistered("Registered backends"))
279 {
280 const Counter* registeredBackendsCounter =
281 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
282 0,
283 0,
284 1.f,
285 "Registered backends",
286 "The number of registered backends",
287 std::string("backends"));
288 BOOST_ASSERT(registeredBackendsCounter);
289 InitializeCounterValue(registeredBackendsCounter->m_Uid);
290 }
291
292 // Register a counter for the number of inferences run
293 if (!m_CounterDirectory.IsCounterRegistered("Inferences run"))
294 {
295 const Counter* inferencesRunCounter =
296 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
297 0,
298 0,
299 1.f,
300 "Inferences run",
301 "The number of inferences run",
302 std::string("inferences"));
303 BOOST_ASSERT(inferencesRunCounter);
304 InitializeCounterValue(inferencesRunCounter->m_Uid);
305 }
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100306}
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100307
Matteo Martincigha84edee2019-10-02 12:50:57 +0100308void ProfilingService::InitializeCounterValue(uint16_t counterUid)
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100309{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100310 // Increase the size of the counter index if necessary
311 if (counterUid >= m_CounterIndex.size())
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100312 {
Matteo Martincigha84edee2019-10-02 12:50:57 +0100313 m_CounterIndex.resize(boost::numeric_cast<size_t>(counterUid) + 1);
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100314 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100315
316 // Create a new atomic counter and add it to the list
317 m_CounterValues.emplace_back(0);
318
319 // Register the new counter to the counter index for quick access
320 std::atomic<uint32_t>* counterValuePtr = &(m_CounterValues.back());
321 m_CounterIndex.at(counterUid) = counterValuePtr;
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100322}
323
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100324void ProfilingService::Reset()
325{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100326 // Stop the profiling service...
Jim Flynn53e46992019-10-14 12:31:10 +0100327 Stop();
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100328
Jim Flynn53e46992019-10-14 12:31:10 +0100329 // ...then delete all the counter data and configuration...
330 m_CounterIndex.clear();
331 m_CounterValues.clear();
332 m_CounterDirectory.Clear();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100333
Jim Flynn53e46992019-10-14 12:31:10 +0100334 // ...finally reset the profiling state machine
335 m_StateMachine.Reset();
336}
337
338void ProfilingService::Stop()
339{
Matteo Martincighd0613b52019-10-09 16:47:04 +0100340 // The order in which we reset/stop the components is not trivial!
341
342 // First stop the threads (Command Handler first)...
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100343 m_CommandHandler.Stop();
344 m_SendCounterPacket.Stop(false);
Matteo Martincighe8485382019-10-10 14:08:21 +0100345 m_PeriodicCounterCapture.Stop();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100346
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100347 // ...then close and destroy the profiling connection...
Jim Flynn53e46992019-10-14 12:31:10 +0100348 if (m_ProfilingConnection != nullptr && m_ProfilingConnection->IsOpen())
349 {
350 m_ProfilingConnection->Close();
351 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100352 m_ProfilingConnection.reset();
353
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100354 // ...then move to the "NotConnected" state
Jim Flynn53e46992019-10-14 12:31:10 +0100355 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100356}
357
Matteo Martincighe8485382019-10-10 14:08:21 +0100358inline void ProfilingService::CheckCounterUid(uint16_t counterUid) const
359{
360 if (!IsCounterRegistered(counterUid))
361 {
362 throw InvalidArgumentException(boost::str(boost::format("Counter UID %1% is not registered") % counterUid));
363 }
364}
365
Keith Davis02356de2019-08-26 18:28:17 +0100366} // namespace profiling
367
Matteo Martincigha84edee2019-10-02 12:50:57 +0100368} // namespace armnn