blob: ee9b8b1701d3fe8ed0ecea6d11d0432d7e5d4b9a [file] [log] [blame]
Keith Davis3201eea2019-10-24 17:30:41 +01001//
Jim Flynnbbfe6032020-07-20 16:57:44 +01002// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
Keith Davis3201eea2019-10-24 17:30:41 +01003// SPDX-License-Identifier: MIT
4//
5
6#include "FileOnlyProfilingConnection.hpp"
Keith Davis3201eea2019-10-24 17:30:41 +01007
8#include <armnn/Exceptions.hpp>
Finn Williamse09fc822020-04-29 13:17:30 +01009#include <common/include/Constants.hpp>
Jim Flynn01d02812020-04-29 21:12:13 +010010#include <common/include/ProfilingException.hpp>
Nikhil Raj7dcc6972021-04-30 15:44:24 +010011#include <common/include/PacketVersionResolver.hpp>
Keith Davis3201eea2019-10-24 17:30:41 +010012
Jim Flynn4e755a52020-03-29 17:48:26 +010013#include <algorithm>
Keith Davis3201eea2019-10-24 17:30:41 +010014#include <iostream>
15#include <thread>
16
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000017namespace arm
Keith Davis3201eea2019-10-24 17:30:41 +010018{
19
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000020namespace pipe
Keith Davis3201eea2019-10-24 17:30:41 +010021{
22
Jim Flynn01d02812020-04-29 21:12:13 +010023std::vector<uint32_t> StreamMetaDataProcessor::GetHeadersAccepted()
24{
25 std::vector<uint32_t> headers;
26 headers.push_back(m_MetaDataPacketHeader);
27 return headers;
28}
29
Jim Flynnbbfe6032020-07-20 16:57:44 +010030void StreamMetaDataProcessor::HandlePacket(const arm::pipe::Packet& packet)
Jim Flynn01d02812020-04-29 21:12:13 +010031{
32 if (packet.GetHeader() != m_MetaDataPacketHeader)
33 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010034 throw arm::pipe::ProfilingException("StreamMetaDataProcessor can only handle Stream Meta Data Packets");
Jim Flynn01d02812020-04-29 21:12:13 +010035 }
36 // determine the endianness of the protocol
37 TargetEndianness endianness;
Jim Flynnbbfe6032020-07-20 16:57:44 +010038 if (ToUint32(packet.GetData(),TargetEndianness::BeWire) == arm::pipe::PIPE_MAGIC)
Jim Flynn01d02812020-04-29 21:12:13 +010039 {
40 endianness = TargetEndianness::BeWire;
41 }
Jim Flynnbbfe6032020-07-20 16:57:44 +010042 else if (ToUint32(packet.GetData(), TargetEndianness::LeWire) == arm::pipe::PIPE_MAGIC)
Jim Flynn01d02812020-04-29 21:12:13 +010043 {
44 endianness = TargetEndianness::LeWire;
45 }
46 else
47 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010048 throw arm::pipe::ProfilingException("Protocol read error. Unable to read the PIPE_MAGIC value.");
Jim Flynn01d02812020-04-29 21:12:13 +010049 }
50 m_FileOnlyProfilingConnection->SetEndianess(endianness);
51 // send back the acknowledgement
52 std::unique_ptr<unsigned char[]> uniqueNullPtr = nullptr;
Jim Flynnbbfe6032020-07-20 16:57:44 +010053 arm::pipe::Packet returnPacket(0x10000, 0, uniqueNullPtr);
Jim Flynn01d02812020-04-29 21:12:13 +010054 m_FileOnlyProfilingConnection->ReturnPacket(returnPacket);
55}
56
57uint32_t StreamMetaDataProcessor::ToUint32(const unsigned char* data, TargetEndianness endianness)
58{
59 // Extract the first 4 bytes starting at data and push them into a 32bit integer based on the
60 // specified endianness.
61 if (endianness == TargetEndianness::BeWire)
62 {
63 return static_cast<uint32_t>(data[0]) << 24 | static_cast<uint32_t>(data[1]) << 16 |
64 static_cast<uint32_t>(data[2]) << 8 | static_cast<uint32_t>(data[3]);
65 }
66 else
67 {
68 return static_cast<uint32_t>(data[3]) << 24 | static_cast<uint32_t>(data[2]) << 16 |
69 static_cast<uint32_t>(data[1]) << 8 | static_cast<uint32_t>(data[0]);
70 }
71}
72
Keith Davis3201eea2019-10-24 17:30:41 +010073FileOnlyProfilingConnection::~FileOnlyProfilingConnection()
74{
Jim Flynn01d02812020-04-29 21:12:13 +010075 try
76 {
77 Close();
78 }
79 catch (...)
80 {
81 // do nothing
82 }
Keith Davis3201eea2019-10-24 17:30:41 +010083}
84
85bool FileOnlyProfilingConnection::IsOpen() const
86{
87 // This type of connection is always open.
88 return true;
89}
90
91void FileOnlyProfilingConnection::Close()
92{
93 // Dump any unread packets out of the queue.
Jim Flynn4e755a52020-03-29 17:48:26 +010094 size_t initialSize = m_PacketQueue.size();
95 for (size_t i = 0; i < initialSize; ++i)
Keith Davis3201eea2019-10-24 17:30:41 +010096 {
97 m_PacketQueue.pop();
98 }
Jim Flynn4e755a52020-03-29 17:48:26 +010099 // dispose of the processing thread
100 m_KeepRunning.store(false);
101 if (m_LocalHandlersThread.joinable())
102 {
103 // make sure the thread wakes up and sees it has to stop
104 m_ConditionPacketReadable.notify_one();
105 m_LocalHandlersThread.join();
106 }
Keith Davis3201eea2019-10-24 17:30:41 +0100107}
108
Keith Davis3201eea2019-10-24 17:30:41 +0100109bool FileOnlyProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
110{
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100111 ARMNN_ASSERT(buffer);
Jim Flynnbbfe6032020-07-20 16:57:44 +0100112 arm::pipe::Packet packet = ReceivePacket(buffer, length);
Jim Flynn4e755a52020-03-29 17:48:26 +0100113 ForwardPacketToHandlers(packet);
Keith Davis3201eea2019-10-24 17:30:41 +0100114 return true;
115}
116
Jim Flynnbbfe6032020-07-20 16:57:44 +0100117void FileOnlyProfilingConnection::ReturnPacket(arm::pipe::Packet& packet)
Jim Flynn01d02812020-04-29 21:12:13 +0100118{
119 {
120 std::lock_guard<std::mutex> lck(m_PacketAvailableMutex);
121 m_PacketQueue.push(std::move(packet));
122 }
123 m_ConditionPacketAvailable.notify_one();
124}
125
Jim Flynnbbfe6032020-07-20 16:57:44 +0100126arm::pipe::Packet FileOnlyProfilingConnection::ReadPacket(uint32_t timeout)
Keith Davis3201eea2019-10-24 17:30:41 +0100127{
Colm Donelan4cace322019-11-20 14:59:12 +0000128 std::unique_lock<std::mutex> lck(m_PacketAvailableMutex);
Finn Williams09ad6f92019-12-19 17:05:18 +0000129
130 // Here we are using m_PacketQueue.empty() as a predicate variable
131 // The conditional variable will wait until packetQueue is not empty or until a timeout
Jim Flynn01d02812020-04-29 21:12:13 +0100132 if (!m_ConditionPacketAvailable.wait_for(lck,
133 std::chrono::milliseconds(timeout),
134 [&]{return !m_PacketQueue.empty();}))
Keith Davis3201eea2019-10-24 17:30:41 +0100135 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100136 arm::pipe::Packet empty;
Jim Flynn01d02812020-04-29 21:12:13 +0100137 return empty;
Keith Davis3201eea2019-10-24 17:30:41 +0100138 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000139
Jim Flynnbbfe6032020-07-20 16:57:44 +0100140 arm::pipe::Packet returnedPacket = std::move(m_PacketQueue.front());
Keith Davis3201eea2019-10-24 17:30:41 +0100141 m_PacketQueue.pop();
142 return returnedPacket;
143}
144
Keith Davis3201eea2019-10-24 17:30:41 +0100145void FileOnlyProfilingConnection::Fail(const std::string& errorMessage)
146{
147 Close();
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000148 throw armnn::RuntimeException(errorMessage);
Keith Davis3201eea2019-10-24 17:30:41 +0100149}
150
Jim Flynn4e755a52020-03-29 17:48:26 +0100151/// Adds a local packet handler to the FileOnlyProfilingConnection. Invoking this will start
152/// a processing thread that will ensure that processing of packets will happen on a separate
153/// thread from the profiling services send thread and will therefore protect against the
154/// profiling message buffer becoming exhausted because packet handling slows the dispatch.
155void FileOnlyProfilingConnection::AddLocalPacketHandler(ILocalPacketHandlerSharedPtr localPacketHandler)
156{
157 m_PacketHandlers.push_back(std::move(localPacketHandler));
158 ILocalPacketHandlerSharedPtr localCopy = m_PacketHandlers.back();
159 localCopy->SetConnection(this);
160 if (localCopy->GetHeadersAccepted().empty())
161 {
162 //this is a universal handler
163 m_UniversalHandlers.push_back(localCopy);
164 }
165 else
166 {
167 for (uint32_t header : localCopy->GetHeadersAccepted())
168 {
169 auto iter = m_IndexedHandlers.find(header);
170 if (iter == m_IndexedHandlers.end())
171 {
172 std::vector<ILocalPacketHandlerSharedPtr> handlers;
173 handlers.push_back(localCopy);
174 m_IndexedHandlers.emplace(std::make_pair(header, handlers));
175 }
176 else
177 {
178 iter->second.push_back(localCopy);
179 }
180 }
181 }
182}
183
184void FileOnlyProfilingConnection::StartProcessingThread()
185{
186 // check if the thread has already started
187 if (m_IsRunning.load())
188 {
189 return;
190 }
191 // make sure if there was one running before it is joined
192 if (m_LocalHandlersThread.joinable())
193 {
194 m_LocalHandlersThread.join();
195 }
196 m_IsRunning.store(true);
197 m_KeepRunning.store(true);
198 m_LocalHandlersThread = std::thread(&FileOnlyProfilingConnection::ServiceLocalHandlers, this);
199}
200
Jim Flynnbbfe6032020-07-20 16:57:44 +0100201void FileOnlyProfilingConnection::ForwardPacketToHandlers(arm::pipe::Packet& packet)
Jim Flynn4e755a52020-03-29 17:48:26 +0100202{
203 if (m_PacketHandlers.empty())
204 {
205 return;
206 }
Jim Flynn01d02812020-04-29 21:12:13 +0100207 if (!m_KeepRunning.load())
Jim Flynn4e755a52020-03-29 17:48:26 +0100208 {
209 return;
210 }
211 {
212 std::unique_lock<std::mutex> readableListLock(m_ReadableMutex);
Jim Flynn01d02812020-04-29 21:12:13 +0100213 if (!m_KeepRunning.load())
Jim Flynn4e755a52020-03-29 17:48:26 +0100214 {
215 return;
216 }
217 m_ReadableList.push(std::move(packet));
218 }
219 m_ConditionPacketReadable.notify_one();
220}
221
222void FileOnlyProfilingConnection::ServiceLocalHandlers()
223{
224 do
225 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100226 arm::pipe::Packet returnedPacket;
Jim Flynn4e755a52020-03-29 17:48:26 +0100227 bool readPacket = false;
228 { // only lock while we are taking the packet off the incoming list
229 std::unique_lock<std::mutex> lck(m_ReadableMutex);
230 if (m_Timeout < 0)
231 {
232 m_ConditionPacketReadable.wait(lck,
233 [&] { return !m_ReadableList.empty(); });
234 }
235 else
236 {
237 m_ConditionPacketReadable.wait_for(lck,
238 std::chrono::milliseconds(std::max(m_Timeout, 1000)),
239 [&] { return !m_ReadableList.empty(); });
240 }
241 if (m_KeepRunning.load())
242 {
243 if (!m_ReadableList.empty())
244 {
245 returnedPacket = std::move(m_ReadableList.front());
246 m_ReadableList.pop();
247 readPacket = true;
248 }
249 }
250 else
251 {
252 ClearReadableList();
253 }
254 }
255 if (m_KeepRunning.load() && readPacket)
256 {
257 DispatchPacketToHandlers(returnedPacket);
258 }
259 } while (m_KeepRunning.load());
260 // make sure the readable list is cleared
261 ClearReadableList();
262 m_IsRunning.store(false);
263}
264
265void FileOnlyProfilingConnection::ClearReadableList()
266{
267 // make sure the incoming packet queue gets emptied
268 size_t initialSize = m_ReadableList.size();
269 for (size_t i = 0; i < initialSize; ++i)
270 {
271 m_ReadableList.pop();
272 }
273}
274
Jim Flynnbbfe6032020-07-20 16:57:44 +0100275void FileOnlyProfilingConnection::DispatchPacketToHandlers(const arm::pipe::Packet& packet)
Jim Flynn4e755a52020-03-29 17:48:26 +0100276{
277 for (auto& delegate : m_UniversalHandlers)
278 {
279 delegate->HandlePacket(packet);
280 }
281 auto iter = m_IndexedHandlers.find(packet.GetHeader());
282 if (iter != m_IndexedHandlers.end())
283 {
Jim Flynn01d02812020-04-29 21:12:13 +0100284 for (auto& delegate : iter->second)
Jim Flynn4e755a52020-03-29 17:48:26 +0100285 {
Jim Flynn01d02812020-04-29 21:12:13 +0100286 try
287 {
288 delegate->HandlePacket(packet);
289 }
Jim Flynnbbfe6032020-07-20 16:57:44 +0100290 catch (const arm::pipe::ProfilingException& ex)
Jim Flynn01d02812020-04-29 21:12:13 +0100291 {
292 Fail(ex.what());
293 }
294 catch (const std::exception& ex)
295 {
296 Fail(ex.what());
297 }
298 catch (...)
299 {
300 Fail("handler failed");
301 }
Jim Flynn4e755a52020-03-29 17:48:26 +0100302 }
303 }
304}
305
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000306} // namespace pipe
Keith Davis3201eea2019-10-24 17:30:41 +0100307
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000308} // namespace arm