blob: cc41fb2d69950a706bacdf6f34eb1b5633edaf4d [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
Keith Davise394bd92019-12-02 15:12:19 +00008#include <armnn/BackendId.hpp>
Derek Lamberti08446972019-11-26 16:38:31 +00009#include <armnn/Logging.hpp>
10
Matteo Martincigha84edee2019-10-02 12:50:57 +010011#include <boost/format.hpp>
12
Keith Davis02356de2019-08-26 18:28:17 +010013namespace armnn
14{
15
16namespace profiling
17{
18
Matteo Martincigha84edee2019-10-02 12:50:57 +010019void ProfilingService::ResetExternalProfilingOptions(const ExternalProfilingOptions& options,
20 bool resetProfilingService)
Keith Davis02356de2019-08-26 18:28:17 +010021{
Matteo Martincigha84edee2019-10-02 12:50:57 +010022 // Update the profiling options
23 m_Options = options;
Keith Davis02356de2019-08-26 18:28:17 +010024
Matteo Martincigh54fb9572019-10-02 12:50:57 +010025 // Check if the profiling service needs to be reset
Matteo Martincigha84edee2019-10-02 12:50:57 +010026 if (resetProfilingService)
Keith Davis02356de2019-08-26 18:28:17 +010027 {
Matteo Martincigha84edee2019-10-02 12:50:57 +010028 // Reset the profiling service
Matteo Martincigh54fb9572019-10-02 12:50:57 +010029 Reset();
Keith Davis02356de2019-08-26 18:28:17 +010030 }
31}
32
Keith Davise394bd92019-12-02 15:12:19 +000033bool ProfilingService::IsProfilingEnabled()
34{
35 return m_Options.m_EnableProfiling;
36}
37
Jim Flynn672d06e2019-10-15 10:18:11 +010038ProfilingState ProfilingService::ConfigureProfilingService(
39 const ExternalProfilingOptions& options,
40 bool resetProfilingService)
41{
42 ResetExternalProfilingOptions(options, resetProfilingService);
43 ProfilingState currentState = m_StateMachine.GetCurrentState();
44 if (options.m_EnableProfiling)
45 {
46 switch (currentState)
47 {
48 case ProfilingState::Uninitialised:
49 Update(); // should transition to NotConnected
50 Update(); // will either stay in NotConnected because there is no server
51 // or will enter WaitingForAck.
52 currentState = m_StateMachine.GetCurrentState();
53 if (currentState == ProfilingState::WaitingForAck)
54 {
55 Update(); // poke it again to send out the metadata packet
56 }
57 currentState = m_StateMachine.GetCurrentState();
58 return currentState;
59 case ProfilingState::NotConnected:
60 Update(); // will either stay in NotConnected because there is no server
61 // or will enter WaitingForAck
62 currentState = m_StateMachine.GetCurrentState();
63 if (currentState == ProfilingState::WaitingForAck)
64 {
65 Update(); // poke it again to send out the metadata packet
66 }
67 currentState = m_StateMachine.GetCurrentState();
68 return currentState;
69 default:
70 return currentState;
71 }
72 }
73 else
74 {
75 // Make sure profiling is shutdown
76 switch (currentState)
77 {
78 case ProfilingState::Uninitialised:
79 case ProfilingState::NotConnected:
80 return currentState;
81 default:
82 Stop();
83 return m_StateMachine.GetCurrentState();
84 }
85 }
86}
87
Matteo Martincigh54fb9572019-10-02 12:50:57 +010088void ProfilingService::Update()
Keith Davis02356de2019-08-26 18:28:17 +010089{
Matteo Martincigh54fb9572019-10-02 12:50:57 +010090 if (!m_Options.m_EnableProfiling)
Matteo Martincigha84edee2019-10-02 12:50:57 +010091 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010092 // Don't run if profiling is disabled
93 return;
Matteo Martincigha84edee2019-10-02 12:50:57 +010094 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +010095
96 ProfilingState currentState = m_StateMachine.GetCurrentState();
97 switch (currentState)
Keith Davis02356de2019-08-26 18:28:17 +010098 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010099 case ProfilingState::Uninitialised:
janeil01811ca552019-12-03 17:01:32 +0000100
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100101 // Initialize the profiling service
102 Initialize();
103
104 // Move to the next state
105 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
106 break;
107 case ProfilingState::NotConnected:
Matteo Martincighd0613b52019-10-09 16:47:04 +0100108 // Stop the command thread (if running)
109 m_CommandHandler.Stop();
110
111 // Stop the send thread (if running)
112 m_SendCounterPacket.Stop(false);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100113
Matteo Martincighe8485382019-10-10 14:08:21 +0100114 // Stop the periodic counter capture thread (if running)
115 m_PeriodicCounterCapture.Stop();
116
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100117 // Reset any existing profiling connection
118 m_ProfilingConnection.reset();
119
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100120 try
Keith Davis02356de2019-08-26 18:28:17 +0100121 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100122 // Setup the profiling connection
Matteo Martincighd0613b52019-10-09 16:47:04 +0100123 BOOST_ASSERT(m_ProfilingConnectionFactory);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100124 m_ProfilingConnection = m_ProfilingConnectionFactory->GetProfilingConnection(m_Options);
Keith Davis02356de2019-08-26 18:28:17 +0100125 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100126 catch (const Exception& e)
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100127 {
Derek Lamberti08446972019-11-26 16:38:31 +0000128 ARMNN_LOG(warning) << "An error has occurred when creating the profiling connection: "
129 << e.what();
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100130 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100131
132 // Move to the next state
133 m_StateMachine.TransitionToState(m_ProfilingConnection
134 ? ProfilingState::WaitingForAck // Profiling connection obtained, wait for ack
135 : ProfilingState::NotConnected); // Profiling connection failed, stay in the
136 // "NotConnected" state
137 break;
138 case ProfilingState::WaitingForAck:
139 BOOST_ASSERT(m_ProfilingConnection);
140
141 // Start the command thread
142 m_CommandHandler.Start(*m_ProfilingConnection);
143
144 // Start the send thread, while in "WaitingForAck" state it'll send out a "Stream MetaData" packet waiting for
145 // a valid "Connection Acknowledged" packet confirming the connection
146 m_SendCounterPacket.Start(*m_ProfilingConnection);
147
148 // The connection acknowledged command handler will automatically transition the state to "Active" once a
149 // valid "Connection Acknowledged" packet has been received
150
151 break;
152 case ProfilingState::Active:
153
Matteo Martincighe8485382019-10-10 14:08:21 +0100154 // The period counter capture thread is started by the Periodic Counter Selection command handler upon
155 // request by an external profiling service
156
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100157 break;
158 default:
159 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
160 % static_cast<int>(currentState)));
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100161 }
Keith Davis02356de2019-08-26 18:28:17 +0100162}
163
Jim Flynn53e46992019-10-14 12:31:10 +0100164void ProfilingService::Disconnect()
165{
166 ProfilingState currentState = m_StateMachine.GetCurrentState();
167 switch (currentState)
168 {
169 case ProfilingState::Uninitialised:
170 case ProfilingState::NotConnected:
171 case ProfilingState::WaitingForAck:
172 return; // NOP
173 case ProfilingState::Active:
174 // Stop the command thread (if running)
175 Stop();
176
177 break;
178 default:
179 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
180 % static_cast<int>(currentState)));
181 }
182}
183
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100184const ICounterDirectory& ProfilingService::GetCounterDirectory() const
185{
186 return m_CounterDirectory;
187}
188
Matteo Martincigha84edee2019-10-02 12:50:57 +0100189ProfilingState ProfilingService::GetCurrentState() const
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100190{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100191 return m_StateMachine.GetCurrentState();
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100192}
193
194uint16_t ProfilingService::GetCounterCount() const
195{
196 return m_CounterDirectory.GetCounterCount();
197}
198
Matteo Martincighe8485382019-10-10 14:08:21 +0100199bool ProfilingService::IsCounterRegistered(uint16_t counterUid) const
200{
201 return counterUid < m_CounterIndex.size();
202}
203
Matteo Martincigha84edee2019-10-02 12:50:57 +0100204uint32_t ProfilingService::GetCounterValue(uint16_t counterUid) const
Keith Davis02356de2019-08-26 18:28:17 +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 return counterValuePtr->load(std::memory_order::memory_order_relaxed);
Keith Davis02356de2019-08-26 18:28:17 +0100210}
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100211
Matteo Martincigha84edee2019-10-02 12:50:57 +0100212void ProfilingService::SetCounterValue(uint16_t counterUid, uint32_t value)
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100213{
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 counterValuePtr->store(value, std::memory_order::memory_order_relaxed);
218}
219
220uint32_t ProfilingService::AddCounterValue(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_add(value, std::memory_order::memory_order_relaxed);
226}
227
228uint32_t ProfilingService::SubtractCounterValue(uint16_t counterUid, uint32_t value)
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->fetch_sub(value, std::memory_order::memory_order_relaxed);
234}
235
236uint32_t ProfilingService::IncrementCounterValue(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
Keith Davise394bd92019-12-02 15:12:19 +0000267 // Register a counter for the number of Network loads
268 if (!m_CounterDirectory.IsCounterRegistered("Network loads"))
Matteo Martincigha84edee2019-10-02 12:50:57 +0100269 {
270 const Counter* loadedNetworksCounter =
Keith Davise394bd92019-12-02 15:12:19 +0000271 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
272 armnn::profiling::NETWORK_LOADS,
273 "ArmNN_Runtime",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100274 0,
275 0,
276 1.f,
Keith Davise394bd92019-12-02 15:12:19 +0000277 "Network loads",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100278 "The number of networks loaded at runtime",
279 std::string("networks"));
280 BOOST_ASSERT(loadedNetworksCounter);
281 InitializeCounterValue(loadedNetworksCounter->m_Uid);
282 }
Keith Davise394bd92019-12-02 15:12:19 +0000283 // Register a counter for the number of unloaded networks
284 if (!m_CounterDirectory.IsCounterRegistered("Network unloads"))
Matteo Martincigha84edee2019-10-02 12:50:57 +0100285 {
Keith Davise394bd92019-12-02 15:12:19 +0000286 const Counter* unloadedNetworksCounter =
287 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
288 armnn::profiling::NETWORK_UNLOADS,
289 "ArmNN_Runtime",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100290 0,
291 0,
292 1.f,
Keith Davise394bd92019-12-02 15:12:19 +0000293 "Network unloads",
294 "The number of networks unloaded at runtime",
295 std::string("networks"));
296 BOOST_ASSERT(unloadedNetworksCounter);
297 InitializeCounterValue(unloadedNetworksCounter->m_Uid);
298 }
299 // Register a counter for the number of registered backends
300 if (!m_CounterDirectory.IsCounterRegistered("Backends registered"))
301 {
302 const Counter* registeredBackendsCounter =
303 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
304 armnn::profiling::REGISTERED_BACKENDS,
305 "ArmNN_Runtime",
306 0,
307 0,
308 1.f,
309 "Backends registered",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100310 "The number of registered backends",
311 std::string("backends"));
312 BOOST_ASSERT(registeredBackendsCounter);
313 InitializeCounterValue(registeredBackendsCounter->m_Uid);
314 }
Keith Davise394bd92019-12-02 15:12:19 +0000315 // Register a counter for the number of registered backends
316 if (!m_CounterDirectory.IsCounterRegistered("Backends unregistered"))
317 {
318 const Counter* unregisteredBackendsCounter =
319 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
320 armnn::profiling::UNREGISTERED_BACKENDS,
321 "ArmNN_Runtime",
322 0,
323 0,
324 1.f,
325 "Backends unregistered",
326 "The number of unregistered backends",
327 std::string("backends"));
328 BOOST_ASSERT(unregisteredBackendsCounter);
329 InitializeCounterValue(unregisteredBackendsCounter->m_Uid);
330 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100331 // Register a counter for the number of inferences run
332 if (!m_CounterDirectory.IsCounterRegistered("Inferences run"))
333 {
334 const Counter* inferencesRunCounter =
Keith Davise394bd92019-12-02 15:12:19 +0000335 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
336 armnn::profiling::INFERENCES_RUN,
337 "ArmNN_Runtime",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100338 0,
339 0,
340 1.f,
341 "Inferences run",
342 "The number of inferences run",
343 std::string("inferences"));
344 BOOST_ASSERT(inferencesRunCounter);
345 InitializeCounterValue(inferencesRunCounter->m_Uid);
346 }
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100347}
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100348
Matteo Martincigha84edee2019-10-02 12:50:57 +0100349void ProfilingService::InitializeCounterValue(uint16_t counterUid)
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100350{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100351 // Increase the size of the counter index if necessary
352 if (counterUid >= m_CounterIndex.size())
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100353 {
Matteo Martincigha84edee2019-10-02 12:50:57 +0100354 m_CounterIndex.resize(boost::numeric_cast<size_t>(counterUid) + 1);
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100355 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100356
357 // Create a new atomic counter and add it to the list
358 m_CounterValues.emplace_back(0);
359
360 // Register the new counter to the counter index for quick access
361 std::atomic<uint32_t>* counterValuePtr = &(m_CounterValues.back());
362 m_CounterIndex.at(counterUid) = counterValuePtr;
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100363}
364
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100365void ProfilingService::Reset()
366{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100367 // Stop the profiling service...
Jim Flynn53e46992019-10-14 12:31:10 +0100368 Stop();
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100369
Jim Flynn53e46992019-10-14 12:31:10 +0100370 // ...then delete all the counter data and configuration...
371 m_CounterIndex.clear();
372 m_CounterValues.clear();
373 m_CounterDirectory.Clear();
Finn Williams09ad6f92019-12-19 17:05:18 +0000374 m_BufferManager.Reset();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100375
Jim Flynn53e46992019-10-14 12:31:10 +0100376 // ...finally reset the profiling state machine
377 m_StateMachine.Reset();
378}
379
380void ProfilingService::Stop()
381{
Matteo Martincighd0613b52019-10-09 16:47:04 +0100382 // The order in which we reset/stop the components is not trivial!
Finn Williams09ad6f92019-12-19 17:05:18 +0000383 // First stop the producing threads
384 // Command Handler first as it is responsible for launching then Periodic Counter capture thread
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100385 m_CommandHandler.Stop();
Matteo Martincighe8485382019-10-10 14:08:21 +0100386 m_PeriodicCounterCapture.Stop();
Finn Williams09ad6f92019-12-19 17:05:18 +0000387 // The the consuming thread
388 m_SendCounterPacket.Stop(false);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100389
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100390 // ...then close and destroy the profiling connection...
Jim Flynn53e46992019-10-14 12:31:10 +0100391 if (m_ProfilingConnection != nullptr && m_ProfilingConnection->IsOpen())
392 {
393 m_ProfilingConnection->Close();
394 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100395 m_ProfilingConnection.reset();
396
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100397 // ...then move to the "NotConnected" state
Jim Flynn53e46992019-10-14 12:31:10 +0100398 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100399}
400
Matteo Martincighe8485382019-10-10 14:08:21 +0100401inline void ProfilingService::CheckCounterUid(uint16_t counterUid) const
402{
403 if (!IsCounterRegistered(counterUid))
404 {
405 throw InvalidArgumentException(boost::str(boost::format("Counter UID %1% is not registered") % counterUid));
406 }
407}
408
janeil01811ca552019-12-03 17:01:32 +0000409ProfilingService::~ProfilingService()
410{
411 Stop();
412}
413
Keith Davis02356de2019-08-26 18:28:17 +0100414} // namespace profiling
415
Matteo Martincigha84edee2019-10-02 12:50:57 +0100416} // namespace armnn