blob: c350fd2860d2063e5136d57fd2d5f1a50d8cd901 [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 <CommandHandlerFunctor.hpp>
14#include <IProfilingConnection.hpp>
Matteo Martincighd0613b52019-10-09 16:47:04 +010015#include <ProfilingService.hpp>
16
17#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 {
Jan Eilers8eb25602020-03-09 12:13:48 +000080 IgnoreUnused(buffer, length);
Derek Lamberti1dd75b32019-12-10 21:23:23 +000081
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 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000142 IgnoreUnused(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 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000161 IgnoreUnused(timeout);
Finn Williams09ad6f92019-12-19 17:05:18 +0000162 // 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 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000184 IgnoreUnused(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
Sadik Armagan3184c902020-03-18 10:57:30 +0000207 SwapProfilingConnectionFactoryHelper(armnn::profiling::ProfilingService& profilingService)
Matteo Martincighd0613b52019-10-09 16:47:04 +0100208 : ProfilingService()
Sadik Armagan3184c902020-03-18 10:57:30 +0000209 , m_ProfilingService(profilingService)
Matteo Martincighd0613b52019-10-09 16:47:04 +0100210 , m_MockProfilingConnectionFactory(new MockProfilingConnectionFactory())
211 , m_BackupProfilingConnectionFactory(nullptr)
Sadik Armagan3184c902020-03-18 10:57:30 +0000212
Matteo Martincighd0613b52019-10-09 16:47:04 +0100213 {
214 BOOST_CHECK(m_MockProfilingConnectionFactory);
Sadik Armagan3184c902020-03-18 10:57:30 +0000215 SwapProfilingConnectionFactory(m_ProfilingService,
Matteo Martincighd0613b52019-10-09 16:47:04 +0100216 m_MockProfilingConnectionFactory.get(),
217 m_BackupProfilingConnectionFactory);
218 BOOST_CHECK(m_BackupProfilingConnectionFactory);
219 }
220 ~SwapProfilingConnectionFactoryHelper()
221 {
222 BOOST_CHECK(m_BackupProfilingConnectionFactory);
223 IProfilingConnectionFactory* temp = nullptr;
Sadik Armagan3184c902020-03-18 10:57:30 +0000224 SwapProfilingConnectionFactory(m_ProfilingService,
Matteo Martincighd0613b52019-10-09 16:47:04 +0100225 m_BackupProfilingConnectionFactory,
226 temp);
227 }
228
229 MockProfilingConnection* GetMockProfilingConnection()
230 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000231 IProfilingConnection* profilingConnection = GetProfilingConnection(m_ProfilingService);
Jan Eilersbb446e52020-04-02 13:56:54 +0100232 return PolymorphicDowncast<MockProfilingConnection*>(profilingConnection);
Matteo Martincighd0613b52019-10-09 16:47:04 +0100233 }
234
Matteo Martincigh8efc5002019-10-10 14:30:29 +0100235 void ForceTransitionToState(ProfilingState newState)
236 {
Sadik Armagan3184c902020-03-18 10:57:30 +0000237 TransitionToState(m_ProfilingService, newState);
Matteo Martincigh8efc5002019-10-10 14:30:29 +0100238 }
239
Finn Williams09ad6f92019-12-19 17:05:18 +0000240 long WaitForPacketsSent(MockProfilingConnection* mockProfilingConnection,
241 MockProfilingConnection::PacketType packetType,
242 uint32_t length = 0,
243 uint32_t timeout = 1000)
Matteo Martincighe8485382019-10-10 14:08:21 +0100244 {
Keith Davis33ed2212020-03-30 10:43:41 +0100245 long packetCount = mockProfilingConnection->CheckForPacket({ packetType, length });
Finn Williams09ad6f92019-12-19 17:05:18 +0000246 // The first packet we receive may not be the one we are looking for, so keep looping until till we find it,
247 // or until WaitForPacketsSent times out
248 while(packetCount == 0 && timeout != 0)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000249 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000250 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
251 // Wait for a notification from the send thread
Sadik Armagan3184c902020-03-18 10:57:30 +0000252 ProfilingService::WaitForPacketSent(m_ProfilingService, timeout);
Finn Williams09ad6f92019-12-19 17:05:18 +0000253
254 std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
255
256 // We need to make sure the timeout does not reset each time we call WaitForPacketsSent
257 uint32_t elapsedTime = static_cast<uint32_t>(
258 std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
259
260 packetCount = mockProfilingConnection->CheckForPacket({packetType, length});
261
262 if (elapsedTime > timeout)
Colm Donelan2ba48d22019-11-29 09:10:59 +0000263 {
Finn Williams09ad6f92019-12-19 17:05:18 +0000264 break;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000265 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000266
267 timeout -= elapsedTime;
Colm Donelan2ba48d22019-11-29 09:10:59 +0000268 }
Finn Williams09ad6f92019-12-19 17:05:18 +0000269 return packetCount;
Matteo Martincighe8485382019-10-10 14:08:21 +0100270 }
271
Matteo Martincighd0613b52019-10-09 16:47:04 +0100272private:
Sadik Armagan3184c902020-03-18 10:57:30 +0000273 armnn::profiling::ProfilingService& m_ProfilingService;
Matteo Martincighd0613b52019-10-09 16:47:04 +0100274 MockProfilingConnectionFactoryPtr m_MockProfilingConnectionFactory;
275 IProfilingConnectionFactory* m_BackupProfilingConnectionFactory;
276};
277
278} // namespace profiling
279
280} // namespace armnn