blob: 27b05a60cf674ffb6ec834f2c6530f164a9fec70 [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)
Sadik Armagan3896b472020-02-10 12:24:15 +0000112 m_SendThread.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
Sadik Armagan3896b472020-02-10 12:24:15 +0000146 m_SendThread.Start(*m_ProfilingConnection);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100147
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
David Monahanc1536d62020-02-12 15:52:35 +0000184// Store a profiling context returned from a backend that support profiling, and register its counters
185void ProfilingService::AddBackendProfilingContext(const BackendId backendId,
186 std::shared_ptr<armnn::profiling::IBackendProfilingContext> profilingContext)
187{
188 BOOST_ASSERT(profilingContext != nullptr);
189 // Register the backend counters
190 m_MaxGlobalCounterId = profilingContext->RegisterCounters(m_MaxGlobalCounterId);
191 m_BackendProfilingContexts.emplace(backendId, std::move(profilingContext));
192}
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100193const ICounterDirectory& ProfilingService::GetCounterDirectory() const
194{
195 return m_CounterDirectory;
196}
197
Jim Flynn97897022020-02-02 12:52:59 +0000198ICounterRegistry& ProfilingService::GetCounterRegistry()
199{
200 return m_CounterDirectory;
201}
202
Matteo Martincigha84edee2019-10-02 12:50:57 +0100203ProfilingState ProfilingService::GetCurrentState() const
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100204{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100205 return m_StateMachine.GetCurrentState();
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100206}
207
208uint16_t ProfilingService::GetCounterCount() const
209{
210 return m_CounterDirectory.GetCounterCount();
211}
212
Matteo Martincighe8485382019-10-10 14:08:21 +0100213bool ProfilingService::IsCounterRegistered(uint16_t counterUid) const
214{
215 return counterUid < m_CounterIndex.size();
216}
217
Matteo Martincigha84edee2019-10-02 12:50:57 +0100218uint32_t ProfilingService::GetCounterValue(uint16_t counterUid) const
Keith Davis02356de2019-08-26 18:28:17 +0100219{
Matteo Martincighe8485382019-10-10 14:08:21 +0100220 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100221 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
222 BOOST_ASSERT(counterValuePtr);
223 return counterValuePtr->load(std::memory_order::memory_order_relaxed);
Keith Davis02356de2019-08-26 18:28:17 +0100224}
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100225
Jim Flynn8e0c7a62020-01-30 14:10:55 +0000226const ICounterMappings& ProfilingService::GetCounterMappings() const
227{
228 return m_CounterIdMap;
229}
230
Jim Flynn97897022020-02-02 12:52:59 +0000231IRegisterCounterMapping& ProfilingService::GetCounterMappingRegistry()
Jim Flynn8e0c7a62020-01-30 14:10:55 +0000232{
233 return m_CounterIdMap;
234}
235
James Conroy2dcd3fe2020-02-06 18:34:52 +0000236CaptureData ProfilingService::GetCaptureData()
237{
238 return m_Holder.GetCaptureData();
239}
240
241void ProfilingService::SetCaptureData(uint32_t capturePeriod, const std::vector<uint16_t>& counterIds)
242{
243 m_Holder.SetCaptureData(capturePeriod, counterIds);
244}
245
Matteo Martincigha84edee2019-10-02 12:50:57 +0100246void ProfilingService::SetCounterValue(uint16_t counterUid, uint32_t value)
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100247{
Matteo Martincighe8485382019-10-10 14:08:21 +0100248 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100249 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
250 BOOST_ASSERT(counterValuePtr);
251 counterValuePtr->store(value, std::memory_order::memory_order_relaxed);
252}
253
254uint32_t ProfilingService::AddCounterValue(uint16_t counterUid, uint32_t value)
255{
Matteo Martincighe8485382019-10-10 14:08:21 +0100256 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100257 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
258 BOOST_ASSERT(counterValuePtr);
259 return counterValuePtr->fetch_add(value, std::memory_order::memory_order_relaxed);
260}
261
262uint32_t ProfilingService::SubtractCounterValue(uint16_t counterUid, uint32_t value)
263{
Matteo Martincighe8485382019-10-10 14:08:21 +0100264 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100265 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
266 BOOST_ASSERT(counterValuePtr);
267 return counterValuePtr->fetch_sub(value, std::memory_order::memory_order_relaxed);
268}
269
270uint32_t ProfilingService::IncrementCounterValue(uint16_t counterUid)
271{
Matteo Martincighe8485382019-10-10 14:08:21 +0100272 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100273 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
274 BOOST_ASSERT(counterValuePtr);
275 return counterValuePtr->operator++(std::memory_order::memory_order_relaxed);
276}
277
Jim Flynn00f3aaf2019-10-24 11:58:06 +0100278ProfilingDynamicGuid ProfilingService::NextGuid()
279{
280 return m_GuidGenerator.NextGuid();
281}
282
283ProfilingStaticGuid ProfilingService::GenerateStaticId(const std::string& str)
284{
285 return m_GuidGenerator.GenerateStaticId(str);
286}
287
Jim Flynn8b200652019-10-24 18:07:44 +0100288std::unique_ptr<ISendTimelinePacket> ProfilingService::GetSendTimelinePacket() const
289{
290 return m_TimelinePacketWriterFactory.GetSendTimelinePacket();
291}
292
Matteo Martincigha84edee2019-10-02 12:50:57 +0100293void ProfilingService::Initialize()
294{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100295 // Register a category for the basic runtime counters
296 if (!m_CounterDirectory.IsCategoryRegistered("ArmNN_Runtime"))
297 {
298 m_CounterDirectory.RegisterCategory("ArmNN_Runtime");
299 }
300
Keith Davise394bd92019-12-02 15:12:19 +0000301 // Register a counter for the number of Network loads
302 if (!m_CounterDirectory.IsCounterRegistered("Network loads"))
Matteo Martincigha84edee2019-10-02 12:50:57 +0100303 {
304 const Counter* loadedNetworksCounter =
Keith Davise394bd92019-12-02 15:12:19 +0000305 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
306 armnn::profiling::NETWORK_LOADS,
307 "ArmNN_Runtime",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100308 0,
309 0,
310 1.f,
Keith Davise394bd92019-12-02 15:12:19 +0000311 "Network loads",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100312 "The number of networks loaded at runtime",
313 std::string("networks"));
314 BOOST_ASSERT(loadedNetworksCounter);
315 InitializeCounterValue(loadedNetworksCounter->m_Uid);
316 }
Keith Davise394bd92019-12-02 15:12:19 +0000317 // Register a counter for the number of unloaded networks
318 if (!m_CounterDirectory.IsCounterRegistered("Network unloads"))
Matteo Martincigha84edee2019-10-02 12:50:57 +0100319 {
Keith Davise394bd92019-12-02 15:12:19 +0000320 const Counter* unloadedNetworksCounter =
321 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
322 armnn::profiling::NETWORK_UNLOADS,
323 "ArmNN_Runtime",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100324 0,
325 0,
326 1.f,
Keith Davise394bd92019-12-02 15:12:19 +0000327 "Network unloads",
328 "The number of networks unloaded at runtime",
329 std::string("networks"));
330 BOOST_ASSERT(unloadedNetworksCounter);
331 InitializeCounterValue(unloadedNetworksCounter->m_Uid);
332 }
333 // Register a counter for the number of registered backends
334 if (!m_CounterDirectory.IsCounterRegistered("Backends registered"))
335 {
336 const Counter* registeredBackendsCounter =
337 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
338 armnn::profiling::REGISTERED_BACKENDS,
339 "ArmNN_Runtime",
340 0,
341 0,
342 1.f,
343 "Backends registered",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100344 "The number of registered backends",
345 std::string("backends"));
346 BOOST_ASSERT(registeredBackendsCounter);
347 InitializeCounterValue(registeredBackendsCounter->m_Uid);
348 }
Keith Davise394bd92019-12-02 15:12:19 +0000349 // Register a counter for the number of registered backends
350 if (!m_CounterDirectory.IsCounterRegistered("Backends unregistered"))
351 {
352 const Counter* unregisteredBackendsCounter =
353 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
354 armnn::profiling::UNREGISTERED_BACKENDS,
355 "ArmNN_Runtime",
356 0,
357 0,
358 1.f,
359 "Backends unregistered",
360 "The number of unregistered backends",
361 std::string("backends"));
362 BOOST_ASSERT(unregisteredBackendsCounter);
363 InitializeCounterValue(unregisteredBackendsCounter->m_Uid);
364 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100365 // Register a counter for the number of inferences run
366 if (!m_CounterDirectory.IsCounterRegistered("Inferences run"))
367 {
368 const Counter* inferencesRunCounter =
Keith Davise394bd92019-12-02 15:12:19 +0000369 m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
370 armnn::profiling::INFERENCES_RUN,
371 "ArmNN_Runtime",
Matteo Martincigha84edee2019-10-02 12:50:57 +0100372 0,
373 0,
374 1.f,
375 "Inferences run",
376 "The number of inferences run",
377 std::string("inferences"));
378 BOOST_ASSERT(inferencesRunCounter);
379 InitializeCounterValue(inferencesRunCounter->m_Uid);
380 }
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100381}
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100382
Matteo Martincigha84edee2019-10-02 12:50:57 +0100383void ProfilingService::InitializeCounterValue(uint16_t counterUid)
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100384{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100385 // Increase the size of the counter index if necessary
386 if (counterUid >= m_CounterIndex.size())
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100387 {
Matteo Martincigha84edee2019-10-02 12:50:57 +0100388 m_CounterIndex.resize(boost::numeric_cast<size_t>(counterUid) + 1);
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100389 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100390
391 // Create a new atomic counter and add it to the list
392 m_CounterValues.emplace_back(0);
393
394 // Register the new counter to the counter index for quick access
395 std::atomic<uint32_t>* counterValuePtr = &(m_CounterValues.back());
396 m_CounterIndex.at(counterUid) = counterValuePtr;
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100397}
398
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100399void ProfilingService::Reset()
400{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100401 // Stop the profiling service...
Jim Flynn53e46992019-10-14 12:31:10 +0100402 Stop();
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100403
Jim Flynn53e46992019-10-14 12:31:10 +0100404 // ...then delete all the counter data and configuration...
405 m_CounterIndex.clear();
406 m_CounterValues.clear();
407 m_CounterDirectory.Clear();
Jim Flynn97897022020-02-02 12:52:59 +0000408 m_CounterIdMap.Reset();
Finn Williams09ad6f92019-12-19 17:05:18 +0000409 m_BufferManager.Reset();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100410
Jim Flynn53e46992019-10-14 12:31:10 +0100411 // ...finally reset the profiling state machine
412 m_StateMachine.Reset();
Colm Donelan1aff3932020-02-05 17:48:59 +0000413 m_BackendProfilingContexts.clear();
David Monahanc1536d62020-02-12 15:52:35 +0000414 m_MaxGlobalCounterId = armnn::profiling::INFERENCES_RUN;
Jim Flynn53e46992019-10-14 12:31:10 +0100415}
416
417void ProfilingService::Stop()
418{
Matteo Martincighd0613b52019-10-09 16:47:04 +0100419 // The order in which we reset/stop the components is not trivial!
Finn Williams09ad6f92019-12-19 17:05:18 +0000420 // First stop the producing threads
421 // Command Handler first as it is responsible for launching then Periodic Counter capture thread
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100422 m_CommandHandler.Stop();
Matteo Martincighe8485382019-10-10 14:08:21 +0100423 m_PeriodicCounterCapture.Stop();
Finn Williams09ad6f92019-12-19 17:05:18 +0000424 // The the consuming thread
Sadik Armagan3896b472020-02-10 12:24:15 +0000425 m_SendThread.Stop(false);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100426
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100427 // ...then close and destroy the profiling connection...
Jim Flynn53e46992019-10-14 12:31:10 +0100428 if (m_ProfilingConnection != nullptr && m_ProfilingConnection->IsOpen())
429 {
430 m_ProfilingConnection->Close();
431 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100432 m_ProfilingConnection.reset();
433
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100434 // ...then move to the "NotConnected" state
Jim Flynn53e46992019-10-14 12:31:10 +0100435 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100436}
437
Matteo Martincighe8485382019-10-10 14:08:21 +0100438inline void ProfilingService::CheckCounterUid(uint16_t counterUid) const
439{
440 if (!IsCounterRegistered(counterUid))
441 {
442 throw InvalidArgumentException(boost::str(boost::format("Counter UID %1% is not registered") % counterUid));
443 }
444}
445
janeil01811ca552019-12-03 17:01:32 +0000446ProfilingService::~ProfilingService()
447{
448 Stop();
449}
450
Keith Davis02356de2019-08-26 18:28:17 +0100451} // namespace profiling
452
Matteo Martincigha84edee2019-10-02 12:50:57 +0100453} // namespace armnn