blob: c4063a583cb704b9d0fd97f7a1ef8589a66a8a7f [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
Jim Flynn8b200652019-10-24 18:07:44 +0100254std::unique_ptr<ISendTimelinePacket> ProfilingService::GetSendTimelinePacket() const
255{
256 return m_TimelinePacketWriterFactory.GetSendTimelinePacket();
257}
258
Matteo Martincigha84edee2019-10-02 12:50:57 +0100259void ProfilingService::Initialize()
260{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100261 // Register a category for the basic runtime counters
262 if (!m_CounterDirectory.IsCategoryRegistered("ArmNN_Runtime"))
263 {
264 m_CounterDirectory.RegisterCategory("ArmNN_Runtime");
265 }
266
267 // Register a counter for the number of loaded networks
268 if (!m_CounterDirectory.IsCounterRegistered("Loaded networks"))
269 {
270 const Counter* loadedNetworksCounter =
271 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
272 0,
273 0,
274 1.f,
275 "Loaded networks",
276 "The number of networks loaded at runtime",
277 std::string("networks"));
278 BOOST_ASSERT(loadedNetworksCounter);
279 InitializeCounterValue(loadedNetworksCounter->m_Uid);
280 }
281
282 // Register a counter for the number of registered backends
283 if (!m_CounterDirectory.IsCounterRegistered("Registered backends"))
284 {
285 const Counter* registeredBackendsCounter =
286 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
287 0,
288 0,
289 1.f,
290 "Registered backends",
291 "The number of registered backends",
292 std::string("backends"));
293 BOOST_ASSERT(registeredBackendsCounter);
294 InitializeCounterValue(registeredBackendsCounter->m_Uid);
295 }
296
297 // Register a counter for the number of inferences run
298 if (!m_CounterDirectory.IsCounterRegistered("Inferences run"))
299 {
300 const Counter* inferencesRunCounter =
301 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
302 0,
303 0,
304 1.f,
305 "Inferences run",
306 "The number of inferences run",
307 std::string("inferences"));
308 BOOST_ASSERT(inferencesRunCounter);
309 InitializeCounterValue(inferencesRunCounter->m_Uid);
310 }
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100311}
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100312
Matteo Martincigha84edee2019-10-02 12:50:57 +0100313void ProfilingService::InitializeCounterValue(uint16_t counterUid)
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100314{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100315 // Increase the size of the counter index if necessary
316 if (counterUid >= m_CounterIndex.size())
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100317 {
Matteo Martincigha84edee2019-10-02 12:50:57 +0100318 m_CounterIndex.resize(boost::numeric_cast<size_t>(counterUid) + 1);
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100319 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100320
321 // Create a new atomic counter and add it to the list
322 m_CounterValues.emplace_back(0);
323
324 // Register the new counter to the counter index for quick access
325 std::atomic<uint32_t>* counterValuePtr = &(m_CounterValues.back());
326 m_CounterIndex.at(counterUid) = counterValuePtr;
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100327}
328
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100329void ProfilingService::Reset()
330{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100331 // Stop the profiling service...
Jim Flynn53e46992019-10-14 12:31:10 +0100332 Stop();
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100333
Jim Flynn53e46992019-10-14 12:31:10 +0100334 // ...then delete all the counter data and configuration...
335 m_CounterIndex.clear();
336 m_CounterValues.clear();
337 m_CounterDirectory.Clear();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100338
Jim Flynn53e46992019-10-14 12:31:10 +0100339 // ...finally reset the profiling state machine
340 m_StateMachine.Reset();
341}
342
343void ProfilingService::Stop()
344{
Matteo Martincighd0613b52019-10-09 16:47:04 +0100345 // The order in which we reset/stop the components is not trivial!
346
347 // First stop the threads (Command Handler first)...
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100348 m_CommandHandler.Stop();
349 m_SendCounterPacket.Stop(false);
Matteo Martincighe8485382019-10-10 14:08:21 +0100350 m_PeriodicCounterCapture.Stop();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100351
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100352 // ...then close and destroy the profiling connection...
Jim Flynn53e46992019-10-14 12:31:10 +0100353 if (m_ProfilingConnection != nullptr && m_ProfilingConnection->IsOpen())
354 {
355 m_ProfilingConnection->Close();
356 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100357 m_ProfilingConnection.reset();
358
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100359 // ...then move to the "NotConnected" state
Jim Flynn53e46992019-10-14 12:31:10 +0100360 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100361}
362
Matteo Martincighe8485382019-10-10 14:08:21 +0100363inline void ProfilingService::CheckCounterUid(uint16_t counterUid) const
364{
365 if (!IsCounterRegistered(counterUid))
366 {
367 throw InvalidArgumentException(boost::str(boost::format("Counter UID %1% is not registered") % counterUid));
368 }
369}
370
Keith Davis02356de2019-08-26 18:28:17 +0100371} // namespace profiling
372
Matteo Martincigha84edee2019-10-02 12:50:57 +0100373} // namespace armnn