blob: cbd8d6bde8124fc59aec3b6fec93be05da3c3561 [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
Jim Flynn6b1bf1a2020-01-22 15:18:49 +000017IProfilingGuidGenerator& IProfilingGuidGenerator::Instance()
18{
19 return ProfilingService::Instance();
20}
21
Matteo Martincigha84edee2019-10-02 12:50:57 +010022void ProfilingService::ResetExternalProfilingOptions(const ExternalProfilingOptions& options,
23 bool resetProfilingService)
Keith Davis02356de2019-08-26 18:28:17 +010024{
Matteo Martincigha84edee2019-10-02 12:50:57 +010025 // Update the profiling options
26 m_Options = options;
Keith Davis02356de2019-08-26 18:28:17 +010027
Matteo Martincigh54fb9572019-10-02 12:50:57 +010028 // Check if the profiling service needs to be reset
Matteo Martincigha84edee2019-10-02 12:50:57 +010029 if (resetProfilingService)
Keith Davis02356de2019-08-26 18:28:17 +010030 {
Matteo Martincigha84edee2019-10-02 12:50:57 +010031 // Reset the profiling service
Matteo Martincigh54fb9572019-10-02 12:50:57 +010032 Reset();
Keith Davis02356de2019-08-26 18:28:17 +010033 }
34}
35
Jim Flynn672d06e2019-10-15 10:18:11 +010036ProfilingState ProfilingService::ConfigureProfilingService(
37 const ExternalProfilingOptions& options,
38 bool resetProfilingService)
39{
40 ResetExternalProfilingOptions(options, resetProfilingService);
41 ProfilingState currentState = m_StateMachine.GetCurrentState();
42 if (options.m_EnableProfiling)
43 {
44 switch (currentState)
45 {
46 case ProfilingState::Uninitialised:
47 Update(); // should transition to NotConnected
48 Update(); // will either stay in NotConnected because there is no server
49 // or will enter WaitingForAck.
50 currentState = m_StateMachine.GetCurrentState();
51 if (currentState == ProfilingState::WaitingForAck)
52 {
53 Update(); // poke it again to send out the metadata packet
54 }
55 currentState = m_StateMachine.GetCurrentState();
56 return currentState;
57 case ProfilingState::NotConnected:
58 Update(); // will either stay in NotConnected because there is no server
59 // or will enter WaitingForAck
60 currentState = m_StateMachine.GetCurrentState();
61 if (currentState == ProfilingState::WaitingForAck)
62 {
63 Update(); // poke it again to send out the metadata packet
64 }
65 currentState = m_StateMachine.GetCurrentState();
66 return currentState;
67 default:
68 return currentState;
69 }
70 }
71 else
72 {
73 // Make sure profiling is shutdown
74 switch (currentState)
75 {
76 case ProfilingState::Uninitialised:
77 case ProfilingState::NotConnected:
78 return currentState;
79 default:
80 Stop();
81 return m_StateMachine.GetCurrentState();
82 }
83 }
84}
85
Matteo Martincigh54fb9572019-10-02 12:50:57 +010086void ProfilingService::Update()
Keith Davis02356de2019-08-26 18:28:17 +010087{
Matteo Martincigh54fb9572019-10-02 12:50:57 +010088 if (!m_Options.m_EnableProfiling)
Matteo Martincigha84edee2019-10-02 12:50:57 +010089 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010090 // Don't run if profiling is disabled
91 return;
Matteo Martincigha84edee2019-10-02 12:50:57 +010092 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +010093
94 ProfilingState currentState = m_StateMachine.GetCurrentState();
95 switch (currentState)
Keith Davis02356de2019-08-26 18:28:17 +010096 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010097 case ProfilingState::Uninitialised:
98 // Initialize the profiling service
99 Initialize();
100
101 // Move to the next state
102 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
103 break;
104 case ProfilingState::NotConnected:
Matteo Martincighd0613b52019-10-09 16:47:04 +0100105 // Stop the command thread (if running)
106 m_CommandHandler.Stop();
107
108 // Stop the send thread (if running)
109 m_SendCounterPacket.Stop(false);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100110
Matteo Martincighe8485382019-10-10 14:08:21 +0100111 // Stop the periodic counter capture thread (if running)
112 m_PeriodicCounterCapture.Stop();
113
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100114 // Reset any existing profiling connection
115 m_ProfilingConnection.reset();
116
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100117 try
Keith Davis02356de2019-08-26 18:28:17 +0100118 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100119 // Setup the profiling connection
Matteo Martincighd0613b52019-10-09 16:47:04 +0100120 BOOST_ASSERT(m_ProfilingConnectionFactory);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100121 m_ProfilingConnection = m_ProfilingConnectionFactory->GetProfilingConnection(m_Options);
Keith Davis02356de2019-08-26 18:28:17 +0100122 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100123 catch (const Exception& e)
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100124 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100125 BOOST_LOG_TRIVIAL(warning) << "An error has occurred when creating the profiling connection: "
Matteo Martincighd0613b52019-10-09 16:47:04 +0100126 << e.what() << std::endl;
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100127 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100128
129 // Move to the next state
130 m_StateMachine.TransitionToState(m_ProfilingConnection
131 ? ProfilingState::WaitingForAck // Profiling connection obtained, wait for ack
132 : ProfilingState::NotConnected); // Profiling connection failed, stay in the
133 // "NotConnected" state
134 break;
135 case ProfilingState::WaitingForAck:
136 BOOST_ASSERT(m_ProfilingConnection);
137
138 // Start the command thread
139 m_CommandHandler.Start(*m_ProfilingConnection);
140
141 // Start the send thread, while in "WaitingForAck" state it'll send out a "Stream MetaData" packet waiting for
142 // a valid "Connection Acknowledged" packet confirming the connection
143 m_SendCounterPacket.Start(*m_ProfilingConnection);
144
145 // The connection acknowledged command handler will automatically transition the state to "Active" once a
146 // valid "Connection Acknowledged" packet has been received
147
148 break;
149 case ProfilingState::Active:
150
Matteo Martincighe8485382019-10-10 14:08:21 +0100151 // The period counter capture thread is started by the Periodic Counter Selection command handler upon
152 // request by an external profiling service
153
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100154 break;
155 default:
156 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
157 % static_cast<int>(currentState)));
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100158 }
Keith Davis02356de2019-08-26 18:28:17 +0100159}
160
Jim Flynn53e46992019-10-14 12:31:10 +0100161void ProfilingService::Disconnect()
162{
163 ProfilingState currentState = m_StateMachine.GetCurrentState();
164 switch (currentState)
165 {
166 case ProfilingState::Uninitialised:
167 case ProfilingState::NotConnected:
168 case ProfilingState::WaitingForAck:
169 return; // NOP
170 case ProfilingState::Active:
171 // Stop the command thread (if running)
172 Stop();
173
174 break;
175 default:
176 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
177 % static_cast<int>(currentState)));
178 }
179}
180
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100181const ICounterDirectory& ProfilingService::GetCounterDirectory() const
182{
183 return m_CounterDirectory;
184}
185
Matteo Martincigha84edee2019-10-02 12:50:57 +0100186ProfilingState ProfilingService::GetCurrentState() const
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100187{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100188 return m_StateMachine.GetCurrentState();
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100189}
190
191uint16_t ProfilingService::GetCounterCount() const
192{
193 return m_CounterDirectory.GetCounterCount();
194}
195
Matteo Martincighe8485382019-10-10 14:08:21 +0100196bool ProfilingService::IsCounterRegistered(uint16_t counterUid) const
197{
198 return counterUid < m_CounterIndex.size();
199}
200
Matteo Martincigha84edee2019-10-02 12:50:57 +0100201uint32_t ProfilingService::GetCounterValue(uint16_t counterUid) const
Keith Davis02356de2019-08-26 18:28:17 +0100202{
Matteo Martincighe8485382019-10-10 14:08:21 +0100203 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100204 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
205 BOOST_ASSERT(counterValuePtr);
206 return counterValuePtr->load(std::memory_order::memory_order_relaxed);
Keith Davis02356de2019-08-26 18:28:17 +0100207}
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100208
Matteo Martincigha84edee2019-10-02 12:50:57 +0100209void ProfilingService::SetCounterValue(uint16_t counterUid, uint32_t value)
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100210{
Matteo Martincighe8485382019-10-10 14:08:21 +0100211 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100212 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
213 BOOST_ASSERT(counterValuePtr);
214 counterValuePtr->store(value, std::memory_order::memory_order_relaxed);
215}
216
217uint32_t ProfilingService::AddCounterValue(uint16_t counterUid, uint32_t value)
218{
Matteo Martincighe8485382019-10-10 14:08:21 +0100219 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100220 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
221 BOOST_ASSERT(counterValuePtr);
222 return counterValuePtr->fetch_add(value, std::memory_order::memory_order_relaxed);
223}
224
225uint32_t ProfilingService::SubtractCounterValue(uint16_t counterUid, uint32_t value)
226{
Matteo Martincighe8485382019-10-10 14:08:21 +0100227 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100228 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
229 BOOST_ASSERT(counterValuePtr);
230 return counterValuePtr->fetch_sub(value, std::memory_order::memory_order_relaxed);
231}
232
233uint32_t ProfilingService::IncrementCounterValue(uint16_t counterUid)
234{
Matteo Martincighe8485382019-10-10 14:08:21 +0100235 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100236 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
237 BOOST_ASSERT(counterValuePtr);
238 return counterValuePtr->operator++(std::memory_order::memory_order_relaxed);
239}
240
241uint32_t ProfilingService::DecrementCounterValue(uint16_t counterUid)
242{
Matteo Martincighe8485382019-10-10 14:08:21 +0100243 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100244 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
245 BOOST_ASSERT(counterValuePtr);
246 return counterValuePtr->operator--(std::memory_order::memory_order_relaxed);
247}
248
Jim Flynn00f3aaf2019-10-24 11:58:06 +0100249ProfilingDynamicGuid ProfilingService::NextGuid()
250{
251 return m_GuidGenerator.NextGuid();
252}
253
254ProfilingStaticGuid ProfilingService::GenerateStaticId(const std::string& str)
255{
256 return m_GuidGenerator.GenerateStaticId(str);
257}
258
Jim Flynn8b200652019-10-24 18:07:44 +0100259std::unique_ptr<ISendTimelinePacket> ProfilingService::GetSendTimelinePacket() const
260{
261 return m_TimelinePacketWriterFactory.GetSendTimelinePacket();
262}
263
Matteo Martincigha84edee2019-10-02 12:50:57 +0100264void ProfilingService::Initialize()
265{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100266 // Register a category for the basic runtime counters
267 if (!m_CounterDirectory.IsCategoryRegistered("ArmNN_Runtime"))
268 {
269 m_CounterDirectory.RegisterCategory("ArmNN_Runtime");
270 }
271
272 // Register a counter for the number of loaded networks
273 if (!m_CounterDirectory.IsCounterRegistered("Loaded networks"))
274 {
275 const Counter* loadedNetworksCounter =
276 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
277 0,
278 0,
279 1.f,
280 "Loaded networks",
281 "The number of networks loaded at runtime",
282 std::string("networks"));
283 BOOST_ASSERT(loadedNetworksCounter);
284 InitializeCounterValue(loadedNetworksCounter->m_Uid);
285 }
286
287 // Register a counter for the number of registered backends
288 if (!m_CounterDirectory.IsCounterRegistered("Registered backends"))
289 {
290 const Counter* registeredBackendsCounter =
291 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
292 0,
293 0,
294 1.f,
295 "Registered backends",
296 "The number of registered backends",
297 std::string("backends"));
298 BOOST_ASSERT(registeredBackendsCounter);
299 InitializeCounterValue(registeredBackendsCounter->m_Uid);
300 }
301
302 // Register a counter for the number of inferences run
303 if (!m_CounterDirectory.IsCounterRegistered("Inferences run"))
304 {
305 const Counter* inferencesRunCounter =
306 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
307 0,
308 0,
309 1.f,
310 "Inferences run",
311 "The number of inferences run",
312 std::string("inferences"));
313 BOOST_ASSERT(inferencesRunCounter);
314 InitializeCounterValue(inferencesRunCounter->m_Uid);
315 }
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100316}
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100317
Matteo Martincigha84edee2019-10-02 12:50:57 +0100318void ProfilingService::InitializeCounterValue(uint16_t counterUid)
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100319{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100320 // Increase the size of the counter index if necessary
321 if (counterUid >= m_CounterIndex.size())
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100322 {
Matteo Martincigha84edee2019-10-02 12:50:57 +0100323 m_CounterIndex.resize(boost::numeric_cast<size_t>(counterUid) + 1);
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100324 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100325
326 // Create a new atomic counter and add it to the list
327 m_CounterValues.emplace_back(0);
328
329 // Register the new counter to the counter index for quick access
330 std::atomic<uint32_t>* counterValuePtr = &(m_CounterValues.back());
331 m_CounterIndex.at(counterUid) = counterValuePtr;
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100332}
333
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100334void ProfilingService::Reset()
335{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100336 // Stop the profiling service...
Jim Flynn53e46992019-10-14 12:31:10 +0100337 Stop();
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100338
Jim Flynn53e46992019-10-14 12:31:10 +0100339 // ...then delete all the counter data and configuration...
340 m_CounterIndex.clear();
341 m_CounterValues.clear();
342 m_CounterDirectory.Clear();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100343
Jim Flynn53e46992019-10-14 12:31:10 +0100344 // ...finally reset the profiling state machine
345 m_StateMachine.Reset();
346}
347
348void ProfilingService::Stop()
349{
Matteo Martincighd0613b52019-10-09 16:47:04 +0100350 // The order in which we reset/stop the components is not trivial!
351
352 // First stop the threads (Command Handler first)...
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100353 m_CommandHandler.Stop();
354 m_SendCounterPacket.Stop(false);
Matteo Martincighe8485382019-10-10 14:08:21 +0100355 m_PeriodicCounterCapture.Stop();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100356
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100357 // ...then close and destroy the profiling connection...
Jim Flynn53e46992019-10-14 12:31:10 +0100358 if (m_ProfilingConnection != nullptr && m_ProfilingConnection->IsOpen())
359 {
360 m_ProfilingConnection->Close();
361 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100362 m_ProfilingConnection.reset();
363
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100364 // ...then move to the "NotConnected" state
Jim Flynn53e46992019-10-14 12:31:10 +0100365 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100366}
367
Matteo Martincighe8485382019-10-10 14:08:21 +0100368inline void ProfilingService::CheckCounterUid(uint16_t counterUid) const
369{
370 if (!IsCounterRegistered(counterUid))
371 {
372 throw InvalidArgumentException(boost::str(boost::format("Counter UID %1% is not registered") % counterUid));
373 }
374}
375
Keith Davis02356de2019-08-26 18:28:17 +0100376} // namespace profiling
377
Matteo Martincigha84edee2019-10-02 12:50:57 +0100378} // namespace armnn