blob: ed3e03db77f95b2ef6ddbeeee3884c140ec16c31 [file] [log] [blame]
Matteo Martincighd0613b52019-10-09 16:47:04 +01001//
Jim Flynn6398a982020-05-27 17:05:21 +01002// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
Matteo Martincighd0613b52019-10-09 16:47:04 +01003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
Jim Flynn64063552020-02-14 10:18:08 +00008#include "ProfilingMocks.hpp"
Matteo Martincighd0613b52019-10-09 16:47:04 +01009
Derek Lamberti08446972019-11-26 16:38:31 +000010#include <armnn/Logging.hpp>
Jan Eilersbb446e52020-04-02 13:56:54 +010011#include <armnn/utility/PolymorphicDowncast.hpp>
Derek Lamberti08446972019-11-26 16:38:31 +000012
Matteo Martincighd0613b52019-10-09 16:47:04 +010013#include <IProfilingConnection.hpp>
Matteo Martincighd0613b52019-10-09 16:47:04 +010014#include <ProfilingService.hpp>
15
Jim Flynnbbfe6032020-07-20 16:57:44 +010016#include <common/include/CommandHandlerFunctor.hpp>
17
18
Sadik Armagan1625efc2021-06-10 18:24:34 +010019#include <doctest/doctest.h>
Matteo Martincighd0613b52019-10-09 16:47:04 +010020
21#include <chrono>
Matteo Martincighd0613b52019-10-09 16:47:04 +010022#include <thread>
23
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000024namespace arm
Matteo Martincighd0613b52019-10-09 16:47:04 +010025{
26
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000027namespace pipe
Matteo Martincighd0613b52019-10-09 16:47:04 +010028{
29
30struct LogLevelSwapper
31{
32public:
33 LogLevelSwapper(armnn::LogSeverity severity)
34 {
35 // Set the new log level
36 armnn::ConfigureLogging(true, true, severity);
37 }
38 ~LogLevelSwapper()
39 {
40 // The default log level for unit tests is "Fatal"
41 armnn::ConfigureLogging(true, true, armnn::LogSeverity::Fatal);
42 }
43};
44
Matteo Martincighd0613b52019-10-09 16:47:04 +010045struct StreamRedirector
46{
47public:
48 StreamRedirector(std::ostream& stream, std::streambuf* newStreamBuffer)
49 : m_Stream(stream)
50 , m_BackupBuffer(m_Stream.rdbuf(newStreamBuffer))
51 {}
Colm Donelan2ba48d22019-11-29 09:10:59 +000052
53 ~StreamRedirector() { CancelRedirect(); }
54
55 void CancelRedirect()
56 {
57 // Only cancel the redirect once.
58 if (m_BackupBuffer != nullptr )
59 {
60 m_Stream.rdbuf(m_BackupBuffer);
61 m_BackupBuffer = nullptr;
62 }
63 }
Matteo Martincighd0613b52019-10-09 16:47:04 +010064
65private:
66 std::ostream& m_Stream;
67 std::streambuf* m_BackupBuffer;
68};
69
70class TestProfilingConnectionBase : public IProfilingConnection
71{
72public:
73 TestProfilingConnectionBase() = default;
74 ~TestProfilingConnectionBase() = default;
75
76 bool IsOpen() const override { return true; }
77
78 void Close() override {}
79
Derek Lamberti1dd75b32019-12-10 21:23:23 +000080 bool WritePacket(const unsigned char* buffer, uint32_t length) override
81 {
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000082 armnn::IgnoreUnused(buffer, length);
Derek Lamberti1dd75b32019-12-10 21:23:23 +000083
84 return false;
85 }
Matteo Martincighd0613b52019-10-09 16:47:04 +010086
Jim Flynnbbfe6032020-07-20 16:57:44 +010087 arm::pipe::Packet ReadPacket(uint32_t timeout) override
Matteo Martincighd0613b52019-10-09 16:47:04 +010088 {
Colm Donelan2ba48d22019-11-29 09:10:59 +000089 // First time we're called return a connection ack packet. After that always timeout.
90 if (m_FirstCall)
91 {
92 m_FirstCall = false;
93 // Return connection acknowledged packet
Jim Flynnbbfe6032020-07-20 16:57:44 +010094 return arm::pipe::Packet(65536);
Colm Donelan2ba48d22019-11-29 09:10:59 +000095 }
96 else
97 {
98 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
Jim Flynnf9db3ef2022-03-08 21:23:44 +000099 throw arm::pipe::TimeoutException("Simulate a timeout error\n");
Colm Donelan2ba48d22019-11-29 09:10:59 +0000100 }
Matteo Martincighd0613b52019-10-09 16:47:04 +0100101 }
Colm Donelan2ba48d22019-11-29 09:10:59 +0000102
103 bool m_FirstCall = true;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100104};
105
106class TestProfilingConnectionTimeoutError : public TestProfilingConnectionBase
107{
108public:
109 TestProfilingConnectionTimeoutError()
110 : m_ReadRequests(0)
111 {}
112
Jim Flynnbbfe6032020-07-20 16:57:44 +0100113 arm::pipe::Packet ReadPacket(uint32_t timeout) override
Matteo Martincighd0613b52019-10-09 16:47:04 +0100114 {
Colm Donelan2ba48d22019-11-29 09:10:59 +0000115 // Return connection acknowledged packet after three timeouts
116 if (m_ReadRequests % 3 == 0)
Matteo Martincighd0613b52019-10-09 16:47:04 +0100117 {
Colm Donelan2ba48d22019-11-29 09:10:59 +0000118 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
119 ++m_ReadRequests;
Jim Flynnf9db3ef2022-03-08 21:23:44 +0000120 throw arm::pipe::TimeoutException("Simulate a timeout error\n");
Matteo Martincighd0613b52019-10-09 16:47:04 +0100121 }
122
Jim Flynnbbfe6032020-07-20 16:57:44 +0100123 return arm::pipe::Packet(65536);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100124 }
125
Colm Donelan2ba48d22019-11-29 09:10:59 +0000126 int ReadCalledCount()
127 {
128 return m_ReadRequests.load();
129 }
130
Matteo Martincighd0613b52019-10-09 16:47:04 +0100131private:
Colm Donelan2ba48d22019-11-29 09:10:59 +0000132 std::atomic<int> m_ReadRequests;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100133};
134
135class TestProfilingConnectionArmnnError : public TestProfilingConnectionBase
136{
137public:
Colm Donelan2ba48d22019-11-29 09:10:59 +0000138 TestProfilingConnectionArmnnError()
139 : m_ReadRequests(0)
140 {}
141
Jim Flynnbbfe6032020-07-20 16:57:44 +0100142 arm::pipe::Packet ReadPacket(uint32_t timeout) override
Matteo Martincighd0613b52019-10-09 16:47:04 +0100143 {
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000144 armnn::IgnoreUnused(timeout);
Colm Donelan2ba48d22019-11-29 09:10:59 +0000145 ++m_ReadRequests;
Jim Flynnf9db3ef2022-03-08 21:23:44 +0000146 throw arm::pipe::ProfilingException("Simulate a non-timeout error");
Matteo Martincighd0613b52019-10-09 16:47:04 +0100147 }
Colm Donelan2ba48d22019-11-29 09:10:59 +0000148
149 int ReadCalledCount()
150 {
151 return m_ReadRequests.load();
152 }
153
154private:
155 std::atomic<int> m_ReadRequests;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100156};
157
Finn Williams09ad6f92019-12-19 17:05:18 +0000158class TestProfilingConnectionBadAckPacket : public TestProfilingConnectionBase
159{
160public:
Jim Flynnbbfe6032020-07-20 16:57:44 +0100161 arm::pipe::Packet ReadPacket(uint32_t timeout) override
Finn Williams09ad6f92019-12-19 17:05:18 +0000162 {
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000163 armnn::IgnoreUnused(timeout);
Finn Williams09ad6f92019-12-19 17:05:18 +0000164 // Connection Acknowledged Packet header (word 0, word 1 is always zero):
165 // 26:31 [6] packet_family: Control Packet Family, value 0b000000
166 // 16:25 [10] packet_id: Packet identifier, value 0b0000000001
167 // 8:15 [8] reserved: Reserved, value 0b00000000
168 // 0:7 [8] reserved: Reserved, value 0b00000000
169 uint32_t packetFamily = 0;
170 uint32_t packetId = 37; // Wrong packet id!!!
171 uint32_t header = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
172
Jim Flynnbbfe6032020-07-20 16:57:44 +0100173 return arm::pipe::Packet(header);
Finn Williams09ad6f92019-12-19 17:05:18 +0000174 }
175};
176
Jim Flynnbbfe6032020-07-20 16:57:44 +0100177class TestFunctorA : public arm::pipe::CommandHandlerFunctor
Matteo Martincighd0613b52019-10-09 16:47:04 +0100178{
179public:
180 using CommandHandlerFunctor::CommandHandlerFunctor;
181
182 int GetCount() { return m_Count; }
183
Jim Flynnbbfe6032020-07-20 16:57:44 +0100184 void operator()(const arm::pipe::Packet& packet) override
Matteo Martincighd0613b52019-10-09 16:47:04 +0100185 {
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000186 armnn::IgnoreUnused(packet);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100187 m_Count++;
188 }
189
190private:
191 int m_Count = 0;
192};
193
194class TestFunctorB : public TestFunctorA
195{
196 using TestFunctorA::TestFunctorA;
197};
198
199class TestFunctorC : public TestFunctorA
200{
201 using TestFunctorA::TestFunctorA;
202};
203
Matteo Martincighd0613b52019-10-09 16:47:04 +0100204class SwapProfilingConnectionFactoryHelper : public ProfilingService
205{
206public:
207 using MockProfilingConnectionFactoryPtr = std::unique_ptr<MockProfilingConnectionFactory>;
208
Jim Flynn34430252022-03-04 15:03:58 +0000209 SwapProfilingConnectionFactoryHelper(uint16_t maxGlobalCounterId,
210 IInitialiseProfilingService& initialiser,
211 ProfilingService& profilingService)
212 : ProfilingService(maxGlobalCounterId, initialiser)
Sadik Armagan3184c902020-03-18 10:57:30 +0000213 , m_ProfilingService(profilingService)
Matteo Martincighd0613b52019-10-09 16:47:04 +0100214 , m_MockProfilingConnectionFactory(new MockProfilingConnectionFactory())
215 , m_BackupProfilingConnectionFactory(nullptr)
Sadik Armagan3184c902020-03-18 10:57:30 +0000216
Matteo Martincighd0613b52019-10-09 16:47:04 +0100217 {
Sadik Armagan1625efc2021-06-10 18:24:34 +0100218 CHECK(m_MockProfilingConnectionFactory);
Sadik Armagan3184c902020-03-18 10:57:30 +0000219 SwapProfilingConnectionFactory(m_ProfilingService,
Matteo Martincighd0613b52019-10-09 16:47:04 +0100220 m_MockProfilingConnectionFactory.get(),
221 m_BackupProfilingConnectionFactory);
Sadik Armagan1625efc2021-06-10 18:24:34 +0100222 CHECK(m_BackupProfilingConnectionFactory);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100223 }
224 ~SwapProfilingConnectionFactoryHelper()
225 {
Sadik Armagan1625efc2021-06-10 18:24:34 +0100226 CHECK(m_BackupProfilingConnectionFactory);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100227 IProfilingConnectionFactory* temp = nullptr;
Sadik Armagan3184c902020-03-18 10:57:30 +0000228 SwapProfilingConnectionFactory(m_ProfilingService,
Matteo Martincighd0613b52019-10-09 16:47:04 +0100229 m_BackupProfilingConnectionFactory,
230 temp);
231 }
232
233 MockProfilingConnection* GetMockProfilingConnection()
234 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000235 IProfilingConnection* profilingConnection = GetProfilingConnection(m_ProfilingService);
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000236 return armnn::PolymorphicDowncast<MockProfilingConnection*>(profilingConnection);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100237 }
238
Matteo Martincigh8efc5002019-10-10 14:30:29 +0100239 void ForceTransitionToState(ProfilingState newState)
240 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000241 TransitionToState(m_ProfilingService, newState);
Matteo Martincigh8efc5002019-10-10 14:30:29 +0100242 }
243
Finn Williams09ad6f92019-12-19 17:05:18 +0000244 long WaitForPacketsSent(MockProfilingConnection* mockProfilingConnection,
245 MockProfilingConnection::PacketType packetType,
246 uint32_t length = 0,
247 uint32_t timeout = 1000)
Matteo Martincighe8485382019-10-10 14:08:21 +0100248 {
Keith Davis33ed2212020-03-30 10:43:41 +0100249 long packetCount = mockProfilingConnection->CheckForPacket({ packetType, length });
Finn Williams09ad6f92019-12-19 17:05:18 +0000250 // The first packet we receive may not be the one we are looking for, so keep looping until till we find it,
251 // or until WaitForPacketsSent times out
252 while(packetCount == 0 && timeout != 0)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000253 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000254 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
255 // Wait for a notification from the send thread
Sadik Armagan3184c902020-03-18 10:57:30 +0000256 ProfilingService::WaitForPacketSent(m_ProfilingService, timeout);
Finn Williams09ad6f92019-12-19 17:05:18 +0000257
258 std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
259
260 // We need to make sure the timeout does not reset each time we call WaitForPacketsSent
261 uint32_t elapsedTime = static_cast<uint32_t>(
262 std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
263
264 packetCount = mockProfilingConnection->CheckForPacket({packetType, length});
265
266 if (elapsedTime > timeout)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000267 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000268 break;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000269 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000270
271 timeout -= elapsedTime;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000272 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000273 return packetCount;
Matteo Martincighe8485382019-10-10 14:08:21 +0100274 }
275
Matteo Martincighd0613b52019-10-09 16:47:04 +0100276private:
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000277 ProfilingService& m_ProfilingService;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100278 MockProfilingConnectionFactoryPtr m_MockProfilingConnectionFactory;
279 IProfilingConnectionFactory* m_BackupProfilingConnectionFactory;
280};
281
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000282} // namespace pipe
Matteo Martincighd0613b52019-10-09 16:47:04 +0100283
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000284} // namespace arm