blob: b481695d492500d6cfc93a2eabd87b6614d52376 [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
Matteo Martincigh54fb9572019-10-02 12:50:57 +010031void ProfilingService::Update()
Keith Davis02356de2019-08-26 18:28:17 +010032{
Matteo Martincigh54fb9572019-10-02 12:50:57 +010033 if (!m_Options.m_EnableProfiling)
Matteo Martincigha84edee2019-10-02 12:50:57 +010034 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010035 // Don't run if profiling is disabled
36 return;
Matteo Martincigha84edee2019-10-02 12:50:57 +010037 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +010038
39 ProfilingState currentState = m_StateMachine.GetCurrentState();
40 switch (currentState)
Keith Davis02356de2019-08-26 18:28:17 +010041 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010042 case ProfilingState::Uninitialised:
43 // Initialize the profiling service
44 Initialize();
45
46 // Move to the next state
47 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
48 break;
49 case ProfilingState::NotConnected:
Matteo Martincighd0613b52019-10-09 16:47:04 +010050 // Stop the command thread (if running)
51 m_CommandHandler.Stop();
52
53 // Stop the send thread (if running)
54 m_SendCounterPacket.Stop(false);
Matteo Martincigh54fb9572019-10-02 12:50:57 +010055
Matteo Martincighe8485382019-10-10 14:08:21 +010056 // Stop the periodic counter capture thread (if running)
57 m_PeriodicCounterCapture.Stop();
58
Matteo Martincigh54fb9572019-10-02 12:50:57 +010059 // Reset any existing profiling connection
60 m_ProfilingConnection.reset();
61
Sadik Armaganbd9e2c52019-09-26 23:13:31 +010062 try
Keith Davis02356de2019-08-26 18:28:17 +010063 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010064 // Setup the profiling connection
Matteo Martincighd0613b52019-10-09 16:47:04 +010065 BOOST_ASSERT(m_ProfilingConnectionFactory);
Matteo Martincigh54fb9572019-10-02 12:50:57 +010066 m_ProfilingConnection = m_ProfilingConnectionFactory->GetProfilingConnection(m_Options);
Keith Davis02356de2019-08-26 18:28:17 +010067 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +010068 catch (const Exception& e)
Sadik Armaganbd9e2c52019-09-26 23:13:31 +010069 {
Matteo Martincigh54fb9572019-10-02 12:50:57 +010070 BOOST_LOG_TRIVIAL(warning) << "An error has occurred when creating the profiling connection: "
Matteo Martincighd0613b52019-10-09 16:47:04 +010071 << e.what() << std::endl;
Sadik Armaganbd9e2c52019-09-26 23:13:31 +010072 }
Matteo Martincigh54fb9572019-10-02 12:50:57 +010073
74 // Move to the next state
75 m_StateMachine.TransitionToState(m_ProfilingConnection
76 ? ProfilingState::WaitingForAck // Profiling connection obtained, wait for ack
77 : ProfilingState::NotConnected); // Profiling connection failed, stay in the
78 // "NotConnected" state
79 break;
80 case ProfilingState::WaitingForAck:
81 BOOST_ASSERT(m_ProfilingConnection);
82
83 // Start the command thread
84 m_CommandHandler.Start(*m_ProfilingConnection);
85
86 // Start the send thread, while in "WaitingForAck" state it'll send out a "Stream MetaData" packet waiting for
87 // a valid "Connection Acknowledged" packet confirming the connection
88 m_SendCounterPacket.Start(*m_ProfilingConnection);
89
90 // The connection acknowledged command handler will automatically transition the state to "Active" once a
91 // valid "Connection Acknowledged" packet has been received
92
93 break;
94 case ProfilingState::Active:
95
Matteo Martincighe8485382019-10-10 14:08:21 +010096 // The period counter capture thread is started by the Periodic Counter Selection command handler upon
97 // request by an external profiling service
98
Matteo Martincigh54fb9572019-10-02 12:50:57 +010099 break;
100 default:
101 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
102 % static_cast<int>(currentState)));
Sadik Armaganbd9e2c52019-09-26 23:13:31 +0100103 }
Keith Davis02356de2019-08-26 18:28:17 +0100104}
105
Jim Flynn53e46992019-10-14 12:31:10 +0100106void ProfilingService::Disconnect()
107{
108 ProfilingState currentState = m_StateMachine.GetCurrentState();
109 switch (currentState)
110 {
111 case ProfilingState::Uninitialised:
112 case ProfilingState::NotConnected:
113 case ProfilingState::WaitingForAck:
114 return; // NOP
115 case ProfilingState::Active:
116 // Stop the command thread (if running)
117 Stop();
118
119 break;
120 default:
121 throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1")
122 % static_cast<int>(currentState)));
123 }
124}
125
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100126const ICounterDirectory& ProfilingService::GetCounterDirectory() const
127{
128 return m_CounterDirectory;
129}
130
Matteo Martincigha84edee2019-10-02 12:50:57 +0100131ProfilingState ProfilingService::GetCurrentState() const
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100132{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100133 return m_StateMachine.GetCurrentState();
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100134}
135
136uint16_t ProfilingService::GetCounterCount() const
137{
138 return m_CounterDirectory.GetCounterCount();
139}
140
Matteo Martincighe8485382019-10-10 14:08:21 +0100141bool ProfilingService::IsCounterRegistered(uint16_t counterUid) const
142{
143 return counterUid < m_CounterIndex.size();
144}
145
Matteo Martincigha84edee2019-10-02 12:50:57 +0100146uint32_t ProfilingService::GetCounterValue(uint16_t counterUid) const
Keith Davis02356de2019-08-26 18:28:17 +0100147{
Matteo Martincighe8485382019-10-10 14:08:21 +0100148 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100149 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
150 BOOST_ASSERT(counterValuePtr);
151 return counterValuePtr->load(std::memory_order::memory_order_relaxed);
Keith Davis02356de2019-08-26 18:28:17 +0100152}
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100153
Matteo Martincigha84edee2019-10-02 12:50:57 +0100154void ProfilingService::SetCounterValue(uint16_t counterUid, uint32_t value)
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100155{
Matteo Martincighe8485382019-10-10 14:08:21 +0100156 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100157 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
158 BOOST_ASSERT(counterValuePtr);
159 counterValuePtr->store(value, std::memory_order::memory_order_relaxed);
160}
161
162uint32_t ProfilingService::AddCounterValue(uint16_t counterUid, uint32_t value)
163{
Matteo Martincighe8485382019-10-10 14:08:21 +0100164 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100165 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
166 BOOST_ASSERT(counterValuePtr);
167 return counterValuePtr->fetch_add(value, std::memory_order::memory_order_relaxed);
168}
169
170uint32_t ProfilingService::SubtractCounterValue(uint16_t counterUid, uint32_t value)
171{
Matteo Martincighe8485382019-10-10 14:08:21 +0100172 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100173 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
174 BOOST_ASSERT(counterValuePtr);
175 return counterValuePtr->fetch_sub(value, std::memory_order::memory_order_relaxed);
176}
177
178uint32_t ProfilingService::IncrementCounterValue(uint16_t counterUid)
179{
Matteo Martincighe8485382019-10-10 14:08:21 +0100180 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100181 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
182 BOOST_ASSERT(counterValuePtr);
183 return counterValuePtr->operator++(std::memory_order::memory_order_relaxed);
184}
185
186uint32_t ProfilingService::DecrementCounterValue(uint16_t counterUid)
187{
Matteo Martincighe8485382019-10-10 14:08:21 +0100188 CheckCounterUid(counterUid);
Matteo Martincigha84edee2019-10-02 12:50:57 +0100189 std::atomic<uint32_t>* counterValuePtr = m_CounterIndex.at(counterUid);
190 BOOST_ASSERT(counterValuePtr);
191 return counterValuePtr->operator--(std::memory_order::memory_order_relaxed);
192}
193
194void ProfilingService::Initialize()
195{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100196 // Register a category for the basic runtime counters
197 if (!m_CounterDirectory.IsCategoryRegistered("ArmNN_Runtime"))
198 {
199 m_CounterDirectory.RegisterCategory("ArmNN_Runtime");
200 }
201
202 // Register a counter for the number of loaded networks
203 if (!m_CounterDirectory.IsCounterRegistered("Loaded networks"))
204 {
205 const Counter* loadedNetworksCounter =
206 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
207 0,
208 0,
209 1.f,
210 "Loaded networks",
211 "The number of networks loaded at runtime",
212 std::string("networks"));
213 BOOST_ASSERT(loadedNetworksCounter);
214 InitializeCounterValue(loadedNetworksCounter->m_Uid);
215 }
216
217 // Register a counter for the number of registered backends
218 if (!m_CounterDirectory.IsCounterRegistered("Registered backends"))
219 {
220 const Counter* registeredBackendsCounter =
221 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
222 0,
223 0,
224 1.f,
225 "Registered backends",
226 "The number of registered backends",
227 std::string("backends"));
228 BOOST_ASSERT(registeredBackendsCounter);
229 InitializeCounterValue(registeredBackendsCounter->m_Uid);
230 }
231
232 // Register a counter for the number of inferences run
233 if (!m_CounterDirectory.IsCounterRegistered("Inferences run"))
234 {
235 const Counter* inferencesRunCounter =
236 m_CounterDirectory.RegisterCounter("ArmNN_Runtime",
237 0,
238 0,
239 1.f,
240 "Inferences run",
241 "The number of inferences run",
242 std::string("inferences"));
243 BOOST_ASSERT(inferencesRunCounter);
244 InitializeCounterValue(inferencesRunCounter->m_Uid);
245 }
FinnWilliamsArmce2d9d12019-09-18 10:28:16 +0100246}
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100247
Matteo Martincigha84edee2019-10-02 12:50:57 +0100248void ProfilingService::InitializeCounterValue(uint16_t counterUid)
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100249{
Matteo Martincigha84edee2019-10-02 12:50:57 +0100250 // Increase the size of the counter index if necessary
251 if (counterUid >= m_CounterIndex.size())
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100252 {
Matteo Martincigha84edee2019-10-02 12:50:57 +0100253 m_CounterIndex.resize(boost::numeric_cast<size_t>(counterUid) + 1);
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100254 }
Matteo Martincigha84edee2019-10-02 12:50:57 +0100255
256 // Create a new atomic counter and add it to the list
257 m_CounterValues.emplace_back(0);
258
259 // Register the new counter to the counter index for quick access
260 std::atomic<uint32_t>* counterValuePtr = &(m_CounterValues.back());
261 m_CounterIndex.at(counterUid) = counterValuePtr;
FinnWilliamsArmf6e534a2019-09-16 15:45:42 +0100262}
263
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100264void ProfilingService::Reset()
265{
266 // Reset the profiling service
Jim Flynn53e46992019-10-14 12:31:10 +0100267 Stop();
268 // ...then delete all the counter data and configuration...
269 m_CounterIndex.clear();
270 m_CounterValues.clear();
271 m_CounterDirectory.Clear();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100272
Jim Flynn53e46992019-10-14 12:31:10 +0100273 // ...finally reset the profiling state machine
274 m_StateMachine.Reset();
275}
276
277void ProfilingService::Stop()
278{
Matteo Martincighd0613b52019-10-09 16:47:04 +0100279 // The order in which we reset/stop the components is not trivial!
280
281 // First stop the threads (Command Handler first)...
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100282 m_CommandHandler.Stop();
283 m_SendCounterPacket.Stop(false);
Matteo Martincighe8485382019-10-10 14:08:21 +0100284 m_PeriodicCounterCapture.Stop();
Matteo Martincighd0613b52019-10-09 16:47:04 +0100285
286 // ...then destroy the profiling connection...
Jim Flynn53e46992019-10-14 12:31:10 +0100287 if (m_ProfilingConnection != nullptr && m_ProfilingConnection->IsOpen())
288 {
289 m_ProfilingConnection->Close();
290 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100291 m_ProfilingConnection.reset();
292
Jim Flynn53e46992019-10-14 12:31:10 +0100293 m_StateMachine.TransitionToState(ProfilingState::NotConnected);
Matteo Martincigh54fb9572019-10-02 12:50:57 +0100294}
295
Matteo Martincighe8485382019-10-10 14:08:21 +0100296inline void ProfilingService::CheckCounterUid(uint16_t counterUid) const
297{
298 if (!IsCounterRegistered(counterUid))
299 {
300 throw InvalidArgumentException(boost::str(boost::format("Counter UID %1% is not registered") % counterUid));
301 }
302}
303
Keith Davis02356de2019-08-26 18:28:17 +0100304} // namespace profiling
305
Matteo Martincigha84edee2019-10-02 12:50:57 +0100306} // namespace armnn