blob: f96a1c89ab3e34b9dd2bd26b2f3b58726c6db735 [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
Matteo Martincighd0613b52019-10-09 16:47:04 +010019#include <boost/test/unit_test.hpp>
20
21#include <chrono>
Matteo Martincighd0613b52019-10-09 16:47:04 +010022#include <thread>
23
24namespace armnn
25{
26
27namespace profiling
28{
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 {
Jan Eilers8eb25602020-03-09 12:13:48 +000082 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));
99 throw armnn::TimeoutException("Simulate a timeout error\n");
100 }
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;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100120 throw armnn::TimeoutException("Simulate a timeout error\n");
121 }
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 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000144 IgnoreUnused(timeout);
Colm Donelan2ba48d22019-11-29 09:10:59 +0000145 ++m_ReadRequests;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100146 throw armnn::Exception("Simulate a non-timeout error");
147 }
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 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000163 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 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000186 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
Sadik Armagan3184c902020-03-18 10:57:30 +0000209 SwapProfilingConnectionFactoryHelper(armnn::profiling::ProfilingService& profilingService)
Matteo Martincighd0613b52019-10-09 16:47:04 +0100210 : ProfilingService()
Sadik Armagan3184c902020-03-18 10:57:30 +0000211 , m_ProfilingService(profilingService)
Matteo Martincighd0613b52019-10-09 16:47:04 +0100212 , m_MockProfilingConnectionFactory(new MockProfilingConnectionFactory())
213 , m_BackupProfilingConnectionFactory(nullptr)
Sadik Armagan3184c902020-03-18 10:57:30 +0000214
Matteo Martincighd0613b52019-10-09 16:47:04 +0100215 {
216 BOOST_CHECK(m_MockProfilingConnectionFactory);
Sadik Armagan3184c902020-03-18 10:57:30 +0000217 SwapProfilingConnectionFactory(m_ProfilingService,
Matteo Martincighd0613b52019-10-09 16:47:04 +0100218 m_MockProfilingConnectionFactory.get(),
219 m_BackupProfilingConnectionFactory);
220 BOOST_CHECK(m_BackupProfilingConnectionFactory);
221 }
222 ~SwapProfilingConnectionFactoryHelper()
223 {
224 BOOST_CHECK(m_BackupProfilingConnectionFactory);
225 IProfilingConnectionFactory* temp = nullptr;
Sadik Armagan3184c902020-03-18 10:57:30 +0000226 SwapProfilingConnectionFactory(m_ProfilingService,
Matteo Martincighd0613b52019-10-09 16:47:04 +0100227 m_BackupProfilingConnectionFactory,
228 temp);
229 }
230
231 MockProfilingConnection* GetMockProfilingConnection()
232 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000233 IProfilingConnection* profilingConnection = GetProfilingConnection(m_ProfilingService);
Jan Eilersbb446e52020-04-02 13:56:54 +0100234 return PolymorphicDowncast<MockProfilingConnection*>(profilingConnection);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100235 }
236
Matteo Martincigh8efc5002019-10-10 14:30:29 +0100237 void ForceTransitionToState(ProfilingState newState)
238 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000239 TransitionToState(m_ProfilingService, newState);
Matteo Martincigh8efc5002019-10-10 14:30:29 +0100240 }
241
Finn Williams09ad6f92019-12-19 17:05:18 +0000242 long WaitForPacketsSent(MockProfilingConnection* mockProfilingConnection,
243 MockProfilingConnection::PacketType packetType,
244 uint32_t length = 0,
245 uint32_t timeout = 1000)
Matteo Martincighe8485382019-10-10 14:08:21 +0100246 {
Keith Davis33ed2212020-03-30 10:43:41 +0100247 long packetCount = mockProfilingConnection->CheckForPacket({ packetType, length });
Finn Williams09ad6f92019-12-19 17:05:18 +0000248 // The first packet we receive may not be the one we are looking for, so keep looping until till we find it,
249 // or until WaitForPacketsSent times out
250 while(packetCount == 0 && timeout != 0)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000251 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000252 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
253 // Wait for a notification from the send thread
Sadik Armagan3184c902020-03-18 10:57:30 +0000254 ProfilingService::WaitForPacketSent(m_ProfilingService, timeout);
Finn Williams09ad6f92019-12-19 17:05:18 +0000255
256 std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
257
258 // We need to make sure the timeout does not reset each time we call WaitForPacketsSent
259 uint32_t elapsedTime = static_cast<uint32_t>(
260 std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
261
262 packetCount = mockProfilingConnection->CheckForPacket({packetType, length});
263
264 if (elapsedTime > timeout)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000265 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000266 break;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000267 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000268
269 timeout -= elapsedTime;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000270 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000271 return packetCount;
Matteo Martincighe8485382019-10-10 14:08:21 +0100272 }
273
Matteo Martincighd0613b52019-10-09 16:47:04 +0100274private:
Sadik Armagan3184c902020-03-18 10:57:30 +0000275 armnn::profiling::ProfilingService& m_ProfilingService;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100276 MockProfilingConnectionFactoryPtr m_MockProfilingConnectionFactory;
277 IProfilingConnectionFactory* m_BackupProfilingConnectionFactory;
278};
279
280} // namespace profiling
281
282} // namespace armnn