blob: 01ea3a2d71eb3df83cfb6cc431e4c92422a8175b [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
Finn Williamse09fc822020-04-29 13:17:30 +01008#include <common/include/Constants.hpp>
Jim Flynn01d02812020-04-29 21:12:13 +01009#include <common/include/ProfilingException.hpp>
Nikhil Raj7dcc6972021-04-30 15:44:24 +010010#include <common/include/PacketVersionResolver.hpp>
Keith Davis3201eea2019-10-24 17:30:41 +010011
Jim Flynn4e755a52020-03-29 17:48:26 +010012#include <algorithm>
Keith Davis3201eea2019-10-24 17:30:41 +010013#include <iostream>
Jim Flynne195a042022-04-12 17:19:28 +010014
15#if defined(ARMNN_DISABLE_THREADS)
16#include <common/include/IgnoreUnused.hpp>
17#endif
Keith Davis3201eea2019-10-24 17:30:41 +010018
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000019namespace arm
Keith Davis3201eea2019-10-24 17:30:41 +010020{
21
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000022namespace pipe
Keith Davis3201eea2019-10-24 17:30:41 +010023{
24
Jim Flynn01d02812020-04-29 21:12:13 +010025std::vector<uint32_t> StreamMetaDataProcessor::GetHeadersAccepted()
26{
27 std::vector<uint32_t> headers;
28 headers.push_back(m_MetaDataPacketHeader);
29 return headers;
30}
31
Jim Flynnbbfe6032020-07-20 16:57:44 +010032void StreamMetaDataProcessor::HandlePacket(const arm::pipe::Packet& packet)
Jim Flynn01d02812020-04-29 21:12:13 +010033{
34 if (packet.GetHeader() != m_MetaDataPacketHeader)
35 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010036 throw arm::pipe::ProfilingException("StreamMetaDataProcessor can only handle Stream Meta Data Packets");
Jim Flynn01d02812020-04-29 21:12:13 +010037 }
38 // determine the endianness of the protocol
39 TargetEndianness endianness;
Jim Flynnbbfe6032020-07-20 16:57:44 +010040 if (ToUint32(packet.GetData(),TargetEndianness::BeWire) == arm::pipe::PIPE_MAGIC)
Jim Flynn01d02812020-04-29 21:12:13 +010041 {
42 endianness = TargetEndianness::BeWire;
43 }
Jim Flynnbbfe6032020-07-20 16:57:44 +010044 else if (ToUint32(packet.GetData(), TargetEndianness::LeWire) == arm::pipe::PIPE_MAGIC)
Jim Flynn01d02812020-04-29 21:12:13 +010045 {
46 endianness = TargetEndianness::LeWire;
47 }
48 else
49 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010050 throw arm::pipe::ProfilingException("Protocol read error. Unable to read the PIPE_MAGIC value.");
Jim Flynn01d02812020-04-29 21:12:13 +010051 }
52 m_FileOnlyProfilingConnection->SetEndianess(endianness);
53 // send back the acknowledgement
54 std::unique_ptr<unsigned char[]> uniqueNullPtr = nullptr;
Jim Flynnbbfe6032020-07-20 16:57:44 +010055 arm::pipe::Packet returnPacket(0x10000, 0, uniqueNullPtr);
Jim Flynn01d02812020-04-29 21:12:13 +010056 m_FileOnlyProfilingConnection->ReturnPacket(returnPacket);
57}
58
59uint32_t StreamMetaDataProcessor::ToUint32(const unsigned char* data, TargetEndianness endianness)
60{
61 // Extract the first 4 bytes starting at data and push them into a 32bit integer based on the
62 // specified endianness.
63 if (endianness == TargetEndianness::BeWire)
64 {
65 return static_cast<uint32_t>(data[0]) << 24 | static_cast<uint32_t>(data[1]) << 16 |
66 static_cast<uint32_t>(data[2]) << 8 | static_cast<uint32_t>(data[3]);
67 }
68 else
69 {
70 return static_cast<uint32_t>(data[3]) << 24 | static_cast<uint32_t>(data[2]) << 16 |
71 static_cast<uint32_t>(data[1]) << 8 | static_cast<uint32_t>(data[0]);
72 }
73}
74
Keith Davis3201eea2019-10-24 17:30:41 +010075FileOnlyProfilingConnection::~FileOnlyProfilingConnection()
76{
Jim Flynn01d02812020-04-29 21:12:13 +010077 try
78 {
79 Close();
80 }
81 catch (...)
82 {
83 // do nothing
84 }
Keith Davis3201eea2019-10-24 17:30:41 +010085}
86
87bool FileOnlyProfilingConnection::IsOpen() const
88{
89 // This type of connection is always open.
90 return true;
91}
92
93void FileOnlyProfilingConnection::Close()
94{
95 // Dump any unread packets out of the queue.
Jim Flynn4e755a52020-03-29 17:48:26 +010096 size_t initialSize = m_PacketQueue.size();
97 for (size_t i = 0; i < initialSize; ++i)
Keith Davis3201eea2019-10-24 17:30:41 +010098 {
99 m_PacketQueue.pop();
100 }
Jim Flynn4e755a52020-03-29 17:48:26 +0100101 // dispose of the processing thread
102 m_KeepRunning.store(false);
Jim Flynne195a042022-04-12 17:19:28 +0100103#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100104 if (m_LocalHandlersThread.joinable())
105 {
106 // make sure the thread wakes up and sees it has to stop
107 m_ConditionPacketReadable.notify_one();
108 m_LocalHandlersThread.join();
109 }
Jim Flynne195a042022-04-12 17:19:28 +0100110#endif
Keith Davis3201eea2019-10-24 17:30:41 +0100111}
112
Keith Davis3201eea2019-10-24 17:30:41 +0100113bool FileOnlyProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
114{
Jim Flynn6730fe92022-03-10 22:57:47 +0000115 ARM_PIPE_ASSERT(buffer);
Jim Flynnbbfe6032020-07-20 16:57:44 +0100116 arm::pipe::Packet packet = ReceivePacket(buffer, length);
Jim Flynn4e755a52020-03-29 17:48:26 +0100117 ForwardPacketToHandlers(packet);
Keith Davis3201eea2019-10-24 17:30:41 +0100118 return true;
119}
120
Jim Flynnbbfe6032020-07-20 16:57:44 +0100121void FileOnlyProfilingConnection::ReturnPacket(arm::pipe::Packet& packet)
Jim Flynn01d02812020-04-29 21:12:13 +0100122{
123 {
Jim Flynne195a042022-04-12 17:19:28 +0100124#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn01d02812020-04-29 21:12:13 +0100125 std::lock_guard<std::mutex> lck(m_PacketAvailableMutex);
Jim Flynne195a042022-04-12 17:19:28 +0100126#endif
Jim Flynn01d02812020-04-29 21:12:13 +0100127 m_PacketQueue.push(std::move(packet));
128 }
Jim Flynne195a042022-04-12 17:19:28 +0100129#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn01d02812020-04-29 21:12:13 +0100130 m_ConditionPacketAvailable.notify_one();
Jim Flynne195a042022-04-12 17:19:28 +0100131#endif
Jim Flynn01d02812020-04-29 21:12:13 +0100132}
133
Jim Flynnbbfe6032020-07-20 16:57:44 +0100134arm::pipe::Packet FileOnlyProfilingConnection::ReadPacket(uint32_t timeout)
Keith Davis3201eea2019-10-24 17:30:41 +0100135{
Jim Flynne195a042022-04-12 17:19:28 +0100136#if !defined(ARMNN_DISABLE_THREADS)
Colm Donelan4cace322019-11-20 14:59:12 +0000137 std::unique_lock<std::mutex> lck(m_PacketAvailableMutex);
Finn Williams09ad6f92019-12-19 17:05:18 +0000138
139 // Here we are using m_PacketQueue.empty() as a predicate variable
140 // The conditional variable will wait until packetQueue is not empty or until a timeout
Jim Flynn01d02812020-04-29 21:12:13 +0100141 if (!m_ConditionPacketAvailable.wait_for(lck,
142 std::chrono::milliseconds(timeout),
143 [&]{return !m_PacketQueue.empty();}))
Keith Davis3201eea2019-10-24 17:30:41 +0100144 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100145 arm::pipe::Packet empty;
Jim Flynn01d02812020-04-29 21:12:13 +0100146 return empty;
Keith Davis3201eea2019-10-24 17:30:41 +0100147 }
Jim Flynne195a042022-04-12 17:19:28 +0100148#else
149 IgnoreUnused(timeout);
150#endif
Finn Williams09ad6f92019-12-19 17:05:18 +0000151
Jim Flynnbbfe6032020-07-20 16:57:44 +0100152 arm::pipe::Packet returnedPacket = std::move(m_PacketQueue.front());
Keith Davis3201eea2019-10-24 17:30:41 +0100153 m_PacketQueue.pop();
154 return returnedPacket;
155}
156
Keith Davis3201eea2019-10-24 17:30:41 +0100157void FileOnlyProfilingConnection::Fail(const std::string& errorMessage)
158{
159 Close();
Jim Flynnf9db3ef2022-03-08 21:23:44 +0000160 throw arm::pipe::ProfilingException(errorMessage);
Keith Davis3201eea2019-10-24 17:30:41 +0100161}
162
Jim Flynn4e755a52020-03-29 17:48:26 +0100163/// Adds a local packet handler to the FileOnlyProfilingConnection. Invoking this will start
164/// a processing thread that will ensure that processing of packets will happen on a separate
165/// thread from the profiling services send thread and will therefore protect against the
166/// profiling message buffer becoming exhausted because packet handling slows the dispatch.
167void FileOnlyProfilingConnection::AddLocalPacketHandler(ILocalPacketHandlerSharedPtr localPacketHandler)
168{
169 m_PacketHandlers.push_back(std::move(localPacketHandler));
170 ILocalPacketHandlerSharedPtr localCopy = m_PacketHandlers.back();
171 localCopy->SetConnection(this);
172 if (localCopy->GetHeadersAccepted().empty())
173 {
174 //this is a universal handler
175 m_UniversalHandlers.push_back(localCopy);
176 }
177 else
178 {
179 for (uint32_t header : localCopy->GetHeadersAccepted())
180 {
181 auto iter = m_IndexedHandlers.find(header);
182 if (iter == m_IndexedHandlers.end())
183 {
184 std::vector<ILocalPacketHandlerSharedPtr> handlers;
185 handlers.push_back(localCopy);
186 m_IndexedHandlers.emplace(std::make_pair(header, handlers));
187 }
188 else
189 {
190 iter->second.push_back(localCopy);
191 }
192 }
193 }
194}
195
196void FileOnlyProfilingConnection::StartProcessingThread()
197{
198 // check if the thread has already started
199 if (m_IsRunning.load())
200 {
201 return;
202 }
203 // make sure if there was one running before it is joined
Jim Flynne195a042022-04-12 17:19:28 +0100204#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100205 if (m_LocalHandlersThread.joinable())
206 {
207 m_LocalHandlersThread.join();
208 }
Jim Flynne195a042022-04-12 17:19:28 +0100209#endif
Jim Flynn4e755a52020-03-29 17:48:26 +0100210 m_IsRunning.store(true);
211 m_KeepRunning.store(true);
Jim Flynne195a042022-04-12 17:19:28 +0100212#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100213 m_LocalHandlersThread = std::thread(&FileOnlyProfilingConnection::ServiceLocalHandlers, this);
Jim Flynne195a042022-04-12 17:19:28 +0100214#endif
Jim Flynn4e755a52020-03-29 17:48:26 +0100215}
216
Jim Flynnbbfe6032020-07-20 16:57:44 +0100217void FileOnlyProfilingConnection::ForwardPacketToHandlers(arm::pipe::Packet& packet)
Jim Flynn4e755a52020-03-29 17:48:26 +0100218{
219 if (m_PacketHandlers.empty())
220 {
221 return;
222 }
Jim Flynn01d02812020-04-29 21:12:13 +0100223 if (!m_KeepRunning.load())
Jim Flynn4e755a52020-03-29 17:48:26 +0100224 {
225 return;
226 }
227 {
Jim Flynne195a042022-04-12 17:19:28 +0100228#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100229 std::unique_lock<std::mutex> readableListLock(m_ReadableMutex);
Jim Flynne195a042022-04-12 17:19:28 +0100230#endif
Jim Flynn01d02812020-04-29 21:12:13 +0100231 if (!m_KeepRunning.load())
Jim Flynn4e755a52020-03-29 17:48:26 +0100232 {
233 return;
234 }
235 m_ReadableList.push(std::move(packet));
236 }
Jim Flynne195a042022-04-12 17:19:28 +0100237#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100238 m_ConditionPacketReadable.notify_one();
Jim Flynne195a042022-04-12 17:19:28 +0100239#endif
Jim Flynn4e755a52020-03-29 17:48:26 +0100240}
241
242void FileOnlyProfilingConnection::ServiceLocalHandlers()
243{
244 do
245 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100246 arm::pipe::Packet returnedPacket;
Jim Flynn4e755a52020-03-29 17:48:26 +0100247 bool readPacket = false;
248 { // only lock while we are taking the packet off the incoming list
Jim Flynne195a042022-04-12 17:19:28 +0100249#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100250 std::unique_lock<std::mutex> lck(m_ReadableMutex);
Jim Flynne195a042022-04-12 17:19:28 +0100251#endif
Jim Flynn4e755a52020-03-29 17:48:26 +0100252 if (m_Timeout < 0)
253 {
Jim Flynne195a042022-04-12 17:19:28 +0100254#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100255 m_ConditionPacketReadable.wait(lck,
256 [&] { return !m_ReadableList.empty(); });
Jim Flynne195a042022-04-12 17:19:28 +0100257#endif
Jim Flynn4e755a52020-03-29 17:48:26 +0100258 }
259 else
260 {
Jim Flynne195a042022-04-12 17:19:28 +0100261#if !defined(ARMNN_DISABLE_THREADS)
Jim Flynn4e755a52020-03-29 17:48:26 +0100262 m_ConditionPacketReadable.wait_for(lck,
263 std::chrono::milliseconds(std::max(m_Timeout, 1000)),
264 [&] { return !m_ReadableList.empty(); });
Jim Flynne195a042022-04-12 17:19:28 +0100265#endif
Jim Flynn4e755a52020-03-29 17:48:26 +0100266 }
267 if (m_KeepRunning.load())
268 {
269 if (!m_ReadableList.empty())
270 {
271 returnedPacket = std::move(m_ReadableList.front());
272 m_ReadableList.pop();
273 readPacket = true;
274 }
275 }
276 else
277 {
278 ClearReadableList();
279 }
280 }
281 if (m_KeepRunning.load() && readPacket)
282 {
283 DispatchPacketToHandlers(returnedPacket);
284 }
285 } while (m_KeepRunning.load());
286 // make sure the readable list is cleared
287 ClearReadableList();
288 m_IsRunning.store(false);
289}
290
291void FileOnlyProfilingConnection::ClearReadableList()
292{
293 // make sure the incoming packet queue gets emptied
294 size_t initialSize = m_ReadableList.size();
295 for (size_t i = 0; i < initialSize; ++i)
296 {
297 m_ReadableList.pop();
298 }
299}
300
Jim Flynnbbfe6032020-07-20 16:57:44 +0100301void FileOnlyProfilingConnection::DispatchPacketToHandlers(const arm::pipe::Packet& packet)
Jim Flynn4e755a52020-03-29 17:48:26 +0100302{
303 for (auto& delegate : m_UniversalHandlers)
304 {
305 delegate->HandlePacket(packet);
306 }
307 auto iter = m_IndexedHandlers.find(packet.GetHeader());
308 if (iter != m_IndexedHandlers.end())
309 {
Jim Flynn01d02812020-04-29 21:12:13 +0100310 for (auto& delegate : iter->second)
Jim Flynn4e755a52020-03-29 17:48:26 +0100311 {
Jim Flynn01d02812020-04-29 21:12:13 +0100312 try
313 {
314 delegate->HandlePacket(packet);
315 }
Jim Flynnbbfe6032020-07-20 16:57:44 +0100316 catch (const arm::pipe::ProfilingException& ex)
Jim Flynn01d02812020-04-29 21:12:13 +0100317 {
318 Fail(ex.what());
319 }
320 catch (const std::exception& ex)
321 {
322 Fail(ex.what());
323 }
324 catch (...)
325 {
326 Fail("handler failed");
327 }
Jim Flynn4e755a52020-03-29 17:48:26 +0100328 }
329 }
330}
331
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000332} // namespace pipe
Keith Davis3201eea2019-10-24 17:30:41 +0100333
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000334} // namespace arm