blob: d6300e642927e11d9f7454c142c602525b4dac48 [file] [log] [blame]
Matteo Martincighd0613b52019-10-09 16:47:04 +01001//
2// Copyright © 2019 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include "SendCounterPacketTests.hpp"
9
Derek Lamberti08446972019-11-26 16:38:31 +000010#include <armnn/Logging.hpp>
11
Matteo Martincighd0613b52019-10-09 16:47:04 +010012#include <CommandHandlerFunctor.hpp>
13#include <IProfilingConnection.hpp>
Matteo Martincighd0613b52019-10-09 16:47:04 +010014#include <ProfilingService.hpp>
15
Narumol Prangnawarat85ad78c2019-11-18 15:34:23 +000016#include <boost/polymorphic_cast.hpp>
Matteo Martincighd0613b52019-10-09 16:47:04 +010017#include <boost/test/unit_test.hpp>
18
19#include <chrono>
Matteo Martincighd0613b52019-10-09 16:47:04 +010020#include <thread>
21
22namespace armnn
23{
24
25namespace profiling
26{
27
28struct LogLevelSwapper
29{
30public:
31 LogLevelSwapper(armnn::LogSeverity severity)
32 {
33 // Set the new log level
34 armnn::ConfigureLogging(true, true, severity);
35 }
36 ~LogLevelSwapper()
37 {
38 // The default log level for unit tests is "Fatal"
39 armnn::ConfigureLogging(true, true, armnn::LogSeverity::Fatal);
40 }
41};
42
Matteo Martincighd0613b52019-10-09 16:47:04 +010043struct StreamRedirector
44{
45public:
46 StreamRedirector(std::ostream& stream, std::streambuf* newStreamBuffer)
47 : m_Stream(stream)
48 , m_BackupBuffer(m_Stream.rdbuf(newStreamBuffer))
49 {}
Colm Donelan2ba48d22019-11-29 09:10:59 +000050
51 ~StreamRedirector() { CancelRedirect(); }
52
53 void CancelRedirect()
54 {
55 // Only cancel the redirect once.
56 if (m_BackupBuffer != nullptr )
57 {
58 m_Stream.rdbuf(m_BackupBuffer);
59 m_BackupBuffer = nullptr;
60 }
61 }
Matteo Martincighd0613b52019-10-09 16:47:04 +010062
63private:
64 std::ostream& m_Stream;
65 std::streambuf* m_BackupBuffer;
66};
67
68class TestProfilingConnectionBase : public IProfilingConnection
69{
70public:
71 TestProfilingConnectionBase() = default;
72 ~TestProfilingConnectionBase() = default;
73
74 bool IsOpen() const override { return true; }
75
76 void Close() override {}
77
Derek Lamberti1dd75b32019-12-10 21:23:23 +000078 bool WritePacket(const unsigned char* buffer, uint32_t length) override
79 {
80 boost::ignore_unused(buffer, length);
81
82 return false;
83 }
Matteo Martincighd0613b52019-10-09 16:47:04 +010084
85 Packet ReadPacket(uint32_t timeout) override
86 {
Colm Donelan2ba48d22019-11-29 09:10:59 +000087 // First time we're called return a connection ack packet. After that always timeout.
88 if (m_FirstCall)
89 {
90 m_FirstCall = false;
91 // Return connection acknowledged packet
92 return Packet(65536);
93 }
94 else
95 {
96 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
97 throw armnn::TimeoutException("Simulate a timeout error\n");
98 }
Matteo Martincighd0613b52019-10-09 16:47:04 +010099 }
Colm Donelan2ba48d22019-11-29 09:10:59 +0000100
101 bool m_FirstCall = true;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100102};
103
104class TestProfilingConnectionTimeoutError : public TestProfilingConnectionBase
105{
106public:
107 TestProfilingConnectionTimeoutError()
108 : m_ReadRequests(0)
109 {}
110
111 Packet ReadPacket(uint32_t timeout) override
112 {
Colm Donelan2ba48d22019-11-29 09:10:59 +0000113 // Return connection acknowledged packet after three timeouts
114 if (m_ReadRequests % 3 == 0)
Matteo Martincighd0613b52019-10-09 16:47:04 +0100115 {
Colm Donelan2ba48d22019-11-29 09:10:59 +0000116 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
117 ++m_ReadRequests;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100118 throw armnn::TimeoutException("Simulate a timeout error\n");
119 }
120
Matteo Martincigh67ef2a52019-10-10 13:29:02 +0100121 return Packet(65536);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100122 }
123
Colm Donelan2ba48d22019-11-29 09:10:59 +0000124 int ReadCalledCount()
125 {
126 return m_ReadRequests.load();
127 }
128
Matteo Martincighd0613b52019-10-09 16:47:04 +0100129private:
Colm Donelan2ba48d22019-11-29 09:10:59 +0000130 std::atomic<int> m_ReadRequests;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100131};
132
133class TestProfilingConnectionArmnnError : public TestProfilingConnectionBase
134{
135public:
Colm Donelan2ba48d22019-11-29 09:10:59 +0000136 TestProfilingConnectionArmnnError()
137 : m_ReadRequests(0)
138 {}
139
Matteo Martincighd0613b52019-10-09 16:47:04 +0100140 Packet ReadPacket(uint32_t timeout) override
141 {
Derek Lamberti1dd75b32019-12-10 21:23:23 +0000142 boost::ignore_unused(timeout);
Colm Donelan2ba48d22019-11-29 09:10:59 +0000143 ++m_ReadRequests;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100144 throw armnn::Exception("Simulate a non-timeout error");
145 }
Colm Donelan2ba48d22019-11-29 09:10:59 +0000146
147 int ReadCalledCount()
148 {
149 return m_ReadRequests.load();
150 }
151
152private:
153 std::atomic<int> m_ReadRequests;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100154};
155
Finn Williams09ad6f92019-12-19 17:05:18 +0000156class TestProfilingConnectionBadAckPacket : public TestProfilingConnectionBase
157{
158public:
159 Packet ReadPacket(uint32_t timeout) override
160 {
161 boost::ignore_unused(timeout);
162 // Connection Acknowledged Packet header (word 0, word 1 is always zero):
163 // 26:31 [6] packet_family: Control Packet Family, value 0b000000
164 // 16:25 [10] packet_id: Packet identifier, value 0b0000000001
165 // 8:15 [8] reserved: Reserved, value 0b00000000
166 // 0:7 [8] reserved: Reserved, value 0b00000000
167 uint32_t packetFamily = 0;
168 uint32_t packetId = 37; // Wrong packet id!!!
169 uint32_t header = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
170
171 return Packet(header);
172 }
173};
174
Matteo Martincighd0613b52019-10-09 16:47:04 +0100175class TestFunctorA : public CommandHandlerFunctor
176{
177public:
178 using CommandHandlerFunctor::CommandHandlerFunctor;
179
180 int GetCount() { return m_Count; }
181
182 void operator()(const Packet& packet) override
183 {
Derek Lamberti1dd75b32019-12-10 21:23:23 +0000184 boost::ignore_unused(packet);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100185 m_Count++;
186 }
187
188private:
189 int m_Count = 0;
190};
191
192class TestFunctorB : public TestFunctorA
193{
194 using TestFunctorA::TestFunctorA;
195};
196
197class TestFunctorC : public TestFunctorA
198{
199 using TestFunctorA::TestFunctorA;
200};
201
Matteo Martincighd0613b52019-10-09 16:47:04 +0100202class SwapProfilingConnectionFactoryHelper : public ProfilingService
203{
204public:
205 using MockProfilingConnectionFactoryPtr = std::unique_ptr<MockProfilingConnectionFactory>;
206
207 SwapProfilingConnectionFactoryHelper()
208 : ProfilingService()
209 , m_MockProfilingConnectionFactory(new MockProfilingConnectionFactory())
210 , m_BackupProfilingConnectionFactory(nullptr)
211 {
212 BOOST_CHECK(m_MockProfilingConnectionFactory);
213 SwapProfilingConnectionFactory(ProfilingService::Instance(),
214 m_MockProfilingConnectionFactory.get(),
215 m_BackupProfilingConnectionFactory);
216 BOOST_CHECK(m_BackupProfilingConnectionFactory);
217 }
218 ~SwapProfilingConnectionFactoryHelper()
219 {
220 BOOST_CHECK(m_BackupProfilingConnectionFactory);
221 IProfilingConnectionFactory* temp = nullptr;
222 SwapProfilingConnectionFactory(ProfilingService::Instance(),
223 m_BackupProfilingConnectionFactory,
224 temp);
225 }
226
227 MockProfilingConnection* GetMockProfilingConnection()
228 {
229 IProfilingConnection* profilingConnection = GetProfilingConnection(ProfilingService::Instance());
230 return boost::polymorphic_downcast<MockProfilingConnection*>(profilingConnection);
231 }
232
Matteo Martincigh8efc5002019-10-10 14:30:29 +0100233 void ForceTransitionToState(ProfilingState newState)
234 {
235 TransitionToState(ProfilingService::Instance(), newState);
236 }
237
Finn Williams09ad6f92019-12-19 17:05:18 +0000238 long WaitForPacketsSent(MockProfilingConnection* mockProfilingConnection,
239 MockProfilingConnection::PacketType packetType,
240 uint32_t length = 0,
241 uint32_t timeout = 1000)
Matteo Martincighe8485382019-10-10 14:08:21 +0100242 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000243 long packetCount = mockProfilingConnection->CheckForPacket({packetType, length});
244 // The first packet we receive may not be the one we are looking for, so keep looping until till we find it,
245 // or until WaitForPacketsSent times out
246 while(packetCount == 0 && timeout != 0)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000247 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000248 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
249 // Wait for a notification from the send thread
250 ProfilingService::WaitForPacketSent(ProfilingService::Instance(), timeout);
251
252 std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
253
254 // We need to make sure the timeout does not reset each time we call WaitForPacketsSent
255 uint32_t elapsedTime = static_cast<uint32_t>(
256 std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
257
258 packetCount = mockProfilingConnection->CheckForPacket({packetType, length});
259
260 if (elapsedTime > timeout)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000261 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000262 break;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000263 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000264
265 timeout -= elapsedTime;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000266 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000267 return packetCount;
Matteo Martincighe8485382019-10-10 14:08:21 +0100268 }
269
Matteo Martincighd0613b52019-10-09 16:47:04 +0100270private:
271 MockProfilingConnectionFactoryPtr m_MockProfilingConnectionFactory;
272 IProfilingConnectionFactory* m_BackupProfilingConnectionFactory;
273};
274
275} // namespace profiling
276
277} // namespace armnn