blob: 23bb4857a6c5a0cbe6c529bb90f63aaa2ba22df0 [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>
14#include <thread>
15
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000016namespace arm
Keith Davis3201eea2019-10-24 17:30:41 +010017{
18
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000019namespace pipe
Keith Davis3201eea2019-10-24 17:30:41 +010020{
21
Jim Flynn01d02812020-04-29 21:12:13 +010022std::vector<uint32_t> StreamMetaDataProcessor::GetHeadersAccepted()
23{
24 std::vector<uint32_t> headers;
25 headers.push_back(m_MetaDataPacketHeader);
26 return headers;
27}
28
Jim Flynnbbfe6032020-07-20 16:57:44 +010029void StreamMetaDataProcessor::HandlePacket(const arm::pipe::Packet& packet)
Jim Flynn01d02812020-04-29 21:12:13 +010030{
31 if (packet.GetHeader() != m_MetaDataPacketHeader)
32 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010033 throw arm::pipe::ProfilingException("StreamMetaDataProcessor can only handle Stream Meta Data Packets");
Jim Flynn01d02812020-04-29 21:12:13 +010034 }
35 // determine the endianness of the protocol
36 TargetEndianness endianness;
Jim Flynnbbfe6032020-07-20 16:57:44 +010037 if (ToUint32(packet.GetData(),TargetEndianness::BeWire) == arm::pipe::PIPE_MAGIC)
Jim Flynn01d02812020-04-29 21:12:13 +010038 {
39 endianness = TargetEndianness::BeWire;
40 }
Jim Flynnbbfe6032020-07-20 16:57:44 +010041 else if (ToUint32(packet.GetData(), TargetEndianness::LeWire) == arm::pipe::PIPE_MAGIC)
Jim Flynn01d02812020-04-29 21:12:13 +010042 {
43 endianness = TargetEndianness::LeWire;
44 }
45 else
46 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010047 throw arm::pipe::ProfilingException("Protocol read error. Unable to read the PIPE_MAGIC value.");
Jim Flynn01d02812020-04-29 21:12:13 +010048 }
49 m_FileOnlyProfilingConnection->SetEndianess(endianness);
50 // send back the acknowledgement
51 std::unique_ptr<unsigned char[]> uniqueNullPtr = nullptr;
Jim Flynnbbfe6032020-07-20 16:57:44 +010052 arm::pipe::Packet returnPacket(0x10000, 0, uniqueNullPtr);
Jim Flynn01d02812020-04-29 21:12:13 +010053 m_FileOnlyProfilingConnection->ReturnPacket(returnPacket);
54}
55
56uint32_t StreamMetaDataProcessor::ToUint32(const unsigned char* data, TargetEndianness endianness)
57{
58 // Extract the first 4 bytes starting at data and push them into a 32bit integer based on the
59 // specified endianness.
60 if (endianness == TargetEndianness::BeWire)
61 {
62 return static_cast<uint32_t>(data[0]) << 24 | static_cast<uint32_t>(data[1]) << 16 |
63 static_cast<uint32_t>(data[2]) << 8 | static_cast<uint32_t>(data[3]);
64 }
65 else
66 {
67 return static_cast<uint32_t>(data[3]) << 24 | static_cast<uint32_t>(data[2]) << 16 |
68 static_cast<uint32_t>(data[1]) << 8 | static_cast<uint32_t>(data[0]);
69 }
70}
71
Keith Davis3201eea2019-10-24 17:30:41 +010072FileOnlyProfilingConnection::~FileOnlyProfilingConnection()
73{
Jim Flynn01d02812020-04-29 21:12:13 +010074 try
75 {
76 Close();
77 }
78 catch (...)
79 {
80 // do nothing
81 }
Keith Davis3201eea2019-10-24 17:30:41 +010082}
83
84bool FileOnlyProfilingConnection::IsOpen() const
85{
86 // This type of connection is always open.
87 return true;
88}
89
90void FileOnlyProfilingConnection::Close()
91{
92 // Dump any unread packets out of the queue.
Jim Flynn4e755a52020-03-29 17:48:26 +010093 size_t initialSize = m_PacketQueue.size();
94 for (size_t i = 0; i < initialSize; ++i)
Keith Davis3201eea2019-10-24 17:30:41 +010095 {
96 m_PacketQueue.pop();
97 }
Jim Flynn4e755a52020-03-29 17:48:26 +010098 // dispose of the processing thread
99 m_KeepRunning.store(false);
100 if (m_LocalHandlersThread.joinable())
101 {
102 // make sure the thread wakes up and sees it has to stop
103 m_ConditionPacketReadable.notify_one();
104 m_LocalHandlersThread.join();
105 }
Keith Davis3201eea2019-10-24 17:30:41 +0100106}
107
Keith Davis3201eea2019-10-24 17:30:41 +0100108bool FileOnlyProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
109{
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100110 ARMNN_ASSERT(buffer);
Jim Flynnbbfe6032020-07-20 16:57:44 +0100111 arm::pipe::Packet packet = ReceivePacket(buffer, length);
Jim Flynn4e755a52020-03-29 17:48:26 +0100112 ForwardPacketToHandlers(packet);
Keith Davis3201eea2019-10-24 17:30:41 +0100113 return true;
114}
115
Jim Flynnbbfe6032020-07-20 16:57:44 +0100116void FileOnlyProfilingConnection::ReturnPacket(arm::pipe::Packet& packet)
Jim Flynn01d02812020-04-29 21:12:13 +0100117{
118 {
119 std::lock_guard<std::mutex> lck(m_PacketAvailableMutex);
120 m_PacketQueue.push(std::move(packet));
121 }
122 m_ConditionPacketAvailable.notify_one();
123}
124
Jim Flynnbbfe6032020-07-20 16:57:44 +0100125arm::pipe::Packet FileOnlyProfilingConnection::ReadPacket(uint32_t timeout)
Keith Davis3201eea2019-10-24 17:30:41 +0100126{
Colm Donelan4cace322019-11-20 14:59:12 +0000127 std::unique_lock<std::mutex> lck(m_PacketAvailableMutex);
Finn Williams09ad6f92019-12-19 17:05:18 +0000128
129 // Here we are using m_PacketQueue.empty() as a predicate variable
130 // The conditional variable will wait until packetQueue is not empty or until a timeout
Jim Flynn01d02812020-04-29 21:12:13 +0100131 if (!m_ConditionPacketAvailable.wait_for(lck,
132 std::chrono::milliseconds(timeout),
133 [&]{return !m_PacketQueue.empty();}))
Keith Davis3201eea2019-10-24 17:30:41 +0100134 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100135 arm::pipe::Packet empty;
Jim Flynn01d02812020-04-29 21:12:13 +0100136 return empty;
Keith Davis3201eea2019-10-24 17:30:41 +0100137 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000138
Jim Flynnbbfe6032020-07-20 16:57:44 +0100139 arm::pipe::Packet returnedPacket = std::move(m_PacketQueue.front());
Keith Davis3201eea2019-10-24 17:30:41 +0100140 m_PacketQueue.pop();
141 return returnedPacket;
142}
143
Keith Davis3201eea2019-10-24 17:30:41 +0100144void FileOnlyProfilingConnection::Fail(const std::string& errorMessage)
145{
146 Close();
Jim Flynnf9db3ef2022-03-08 21:23:44 +0000147 throw arm::pipe::ProfilingException(errorMessage);
Keith Davis3201eea2019-10-24 17:30:41 +0100148}
149
Jim Flynn4e755a52020-03-29 17:48:26 +0100150/// Adds a local packet handler to the FileOnlyProfilingConnection. Invoking this will start
151/// a processing thread that will ensure that processing of packets will happen on a separate
152/// thread from the profiling services send thread and will therefore protect against the
153/// profiling message buffer becoming exhausted because packet handling slows the dispatch.
154void FileOnlyProfilingConnection::AddLocalPacketHandler(ILocalPacketHandlerSharedPtr localPacketHandler)
155{
156 m_PacketHandlers.push_back(std::move(localPacketHandler));
157 ILocalPacketHandlerSharedPtr localCopy = m_PacketHandlers.back();
158 localCopy->SetConnection(this);
159 if (localCopy->GetHeadersAccepted().empty())
160 {
161 //this is a universal handler
162 m_UniversalHandlers.push_back(localCopy);
163 }
164 else
165 {
166 for (uint32_t header : localCopy->GetHeadersAccepted())
167 {
168 auto iter = m_IndexedHandlers.find(header);
169 if (iter == m_IndexedHandlers.end())
170 {
171 std::vector<ILocalPacketHandlerSharedPtr> handlers;
172 handlers.push_back(localCopy);
173 m_IndexedHandlers.emplace(std::make_pair(header, handlers));
174 }
175 else
176 {
177 iter->second.push_back(localCopy);
178 }
179 }
180 }
181}
182
183void FileOnlyProfilingConnection::StartProcessingThread()
184{
185 // check if the thread has already started
186 if (m_IsRunning.load())
187 {
188 return;
189 }
190 // make sure if there was one running before it is joined
191 if (m_LocalHandlersThread.joinable())
192 {
193 m_LocalHandlersThread.join();
194 }
195 m_IsRunning.store(true);
196 m_KeepRunning.store(true);
197 m_LocalHandlersThread = std::thread(&FileOnlyProfilingConnection::ServiceLocalHandlers, this);
198}
199
Jim Flynnbbfe6032020-07-20 16:57:44 +0100200void FileOnlyProfilingConnection::ForwardPacketToHandlers(arm::pipe::Packet& packet)
Jim Flynn4e755a52020-03-29 17:48:26 +0100201{
202 if (m_PacketHandlers.empty())
203 {
204 return;
205 }
Jim Flynn01d02812020-04-29 21:12:13 +0100206 if (!m_KeepRunning.load())
Jim Flynn4e755a52020-03-29 17:48:26 +0100207 {
208 return;
209 }
210 {
211 std::unique_lock<std::mutex> readableListLock(m_ReadableMutex);
Jim Flynn01d02812020-04-29 21:12:13 +0100212 if (!m_KeepRunning.load())
Jim Flynn4e755a52020-03-29 17:48:26 +0100213 {
214 return;
215 }
216 m_ReadableList.push(std::move(packet));
217 }
218 m_ConditionPacketReadable.notify_one();
219}
220
221void FileOnlyProfilingConnection::ServiceLocalHandlers()
222{
223 do
224 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100225 arm::pipe::Packet returnedPacket;
Jim Flynn4e755a52020-03-29 17:48:26 +0100226 bool readPacket = false;
227 { // only lock while we are taking the packet off the incoming list
228 std::unique_lock<std::mutex> lck(m_ReadableMutex);
229 if (m_Timeout < 0)
230 {
231 m_ConditionPacketReadable.wait(lck,
232 [&] { return !m_ReadableList.empty(); });
233 }
234 else
235 {
236 m_ConditionPacketReadable.wait_for(lck,
237 std::chrono::milliseconds(std::max(m_Timeout, 1000)),
238 [&] { return !m_ReadableList.empty(); });
239 }
240 if (m_KeepRunning.load())
241 {
242 if (!m_ReadableList.empty())
243 {
244 returnedPacket = std::move(m_ReadableList.front());
245 m_ReadableList.pop();
246 readPacket = true;
247 }
248 }
249 else
250 {
251 ClearReadableList();
252 }
253 }
254 if (m_KeepRunning.load() && readPacket)
255 {
256 DispatchPacketToHandlers(returnedPacket);
257 }
258 } while (m_KeepRunning.load());
259 // make sure the readable list is cleared
260 ClearReadableList();
261 m_IsRunning.store(false);
262}
263
264void FileOnlyProfilingConnection::ClearReadableList()
265{
266 // make sure the incoming packet queue gets emptied
267 size_t initialSize = m_ReadableList.size();
268 for (size_t i = 0; i < initialSize; ++i)
269 {
270 m_ReadableList.pop();
271 }
272}
273
Jim Flynnbbfe6032020-07-20 16:57:44 +0100274void FileOnlyProfilingConnection::DispatchPacketToHandlers(const arm::pipe::Packet& packet)
Jim Flynn4e755a52020-03-29 17:48:26 +0100275{
276 for (auto& delegate : m_UniversalHandlers)
277 {
278 delegate->HandlePacket(packet);
279 }
280 auto iter = m_IndexedHandlers.find(packet.GetHeader());
281 if (iter != m_IndexedHandlers.end())
282 {
Jim Flynn01d02812020-04-29 21:12:13 +0100283 for (auto& delegate : iter->second)
Jim Flynn4e755a52020-03-29 17:48:26 +0100284 {
Jim Flynn01d02812020-04-29 21:12:13 +0100285 try
286 {
287 delegate->HandlePacket(packet);
288 }
Jim Flynnbbfe6032020-07-20 16:57:44 +0100289 catch (const arm::pipe::ProfilingException& ex)
Jim Flynn01d02812020-04-29 21:12:13 +0100290 {
291 Fail(ex.what());
292 }
293 catch (const std::exception& ex)
294 {
295 Fail(ex.what());
296 }
297 catch (...)
298 {
299 Fail("handler failed");
300 }
Jim Flynn4e755a52020-03-29 17:48:26 +0100301 }
302 }
303}
304
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000305} // namespace pipe
Keith Davis3201eea2019-10-24 17:30:41 +0100306
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000307} // namespace arm