IVGCVSW-5301 Remove all boost::numeric_cast from armnn/src/profiling
[platform/upstream/armnn.git] / src / profiling / test / ProfilingTests.cpp
1 //
2 // Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "ProfilingTests.hpp"
7 #include "ProfilingTestUtils.hpp"
8
9 #include <backends/BackendProfiling.hpp>
10 #include <common/include/EncodeVersion.hpp>
11 #include <common/include/PacketVersionResolver.hpp>
12 #include <common/include/SwTrace.hpp>
13 #include <CommandHandler.hpp>
14 #include <ConnectionAcknowledgedCommandHandler.hpp>
15 #include <CounterDirectory.hpp>
16 #include <CounterIdMap.hpp>
17 #include <Holder.hpp>
18 #include <ICounterValues.hpp>
19 #include <PeriodicCounterCapture.hpp>
20 #include <PeriodicCounterSelectionCommandHandler.hpp>
21 #include <ProfilingStateMachine.hpp>
22 #include <ProfilingUtils.hpp>
23 #include <RegisterBackendCounters.hpp>
24 #include <RequestCounterDirectoryCommandHandler.hpp>
25 #include <Runtime.hpp>
26 #include <SocketProfilingConnection.hpp>
27 #include <SendCounterPacket.hpp>
28 #include <SendThread.hpp>
29 #include <SendTimelinePacket.hpp>
30
31 #include <armnn/Conversion.hpp>
32 #include <armnn/Types.hpp>
33
34 #include <armnn/Utils.hpp>
35 #include <armnn/utility/IgnoreUnused.hpp>
36 #include <armnn/utility/NumericCast.hpp>
37
38 #include <common/include/CommandHandlerKey.hpp>
39 #include <common/include/CommandHandlerRegistry.hpp>
40 #include <common/include/SocketConnectionException.hpp>
41 #include <common/include/Packet.hpp>
42
43 #include <cstdint>
44 #include <cstring>
45 #include <iostream>
46 #include <limits>
47 #include <map>
48 #include <random>
49
50
51 using namespace armnn::profiling;
52 using PacketType = MockProfilingConnection::PacketType;
53
54 BOOST_AUTO_TEST_SUITE(ExternalProfiling)
55
56 BOOST_AUTO_TEST_CASE(CheckCommandHandlerKeyComparisons)
57 {
58     arm::pipe::CommandHandlerKey testKey1_0(1, 1, 1);
59     arm::pipe::CommandHandlerKey testKey1_1(1, 1, 1);
60     arm::pipe::CommandHandlerKey testKey1_2(1, 2, 1);
61
62     arm::pipe::CommandHandlerKey testKey0(0, 1, 1);
63     arm::pipe::CommandHandlerKey testKey1(0, 1, 1);
64     arm::pipe::CommandHandlerKey testKey2(0, 1, 1);
65     arm::pipe::CommandHandlerKey testKey3(0, 0, 0);
66     arm::pipe::CommandHandlerKey testKey4(0, 2, 2);
67     arm::pipe::CommandHandlerKey testKey5(0, 0, 2);
68
69     BOOST_CHECK(testKey1_0 > testKey0);
70     BOOST_CHECK(testKey1_0 == testKey1_1);
71     BOOST_CHECK(testKey1_0 < testKey1_2);
72
73     BOOST_CHECK(testKey1 < testKey4);
74     BOOST_CHECK(testKey1 > testKey3);
75     BOOST_CHECK(testKey1 <= testKey4);
76     BOOST_CHECK(testKey1 >= testKey3);
77     BOOST_CHECK(testKey1 <= testKey2);
78     BOOST_CHECK(testKey1 >= testKey2);
79     BOOST_CHECK(testKey1 == testKey2);
80     BOOST_CHECK(testKey1 == testKey1);
81
82     BOOST_CHECK(!(testKey1 == testKey5));
83     BOOST_CHECK(!(testKey1 != testKey1));
84     BOOST_CHECK(testKey1 != testKey5);
85
86     BOOST_CHECK(testKey1 == testKey2 && testKey2 == testKey1);
87     BOOST_CHECK(testKey0 == testKey1 && testKey1 == testKey2 && testKey0 == testKey2);
88
89     BOOST_CHECK(testKey1.GetPacketId() == 1);
90     BOOST_CHECK(testKey1.GetVersion() == 1);
91
92     std::vector<arm::pipe::CommandHandlerKey> vect = {
93         arm::pipe::CommandHandlerKey(0, 0, 1), arm::pipe::CommandHandlerKey(0, 2, 0),
94         arm::pipe::CommandHandlerKey(0, 1, 0), arm::pipe::CommandHandlerKey(0, 2, 1),
95         arm::pipe::CommandHandlerKey(0, 1, 1), arm::pipe::CommandHandlerKey(0, 0, 1),
96         arm::pipe::CommandHandlerKey(0, 2, 0), arm::pipe::CommandHandlerKey(0, 0, 0) };
97
98     std::sort(vect.begin(), vect.end());
99
100     std::vector<arm::pipe::CommandHandlerKey> expectedVect = {
101         arm::pipe::CommandHandlerKey(0, 0, 0), arm::pipe::CommandHandlerKey(0, 0, 1),
102         arm::pipe::CommandHandlerKey(0, 0, 1), arm::pipe::CommandHandlerKey(0, 1, 0),
103         arm::pipe::CommandHandlerKey(0, 1, 1), arm::pipe::CommandHandlerKey(0, 2, 0),
104         arm::pipe::CommandHandlerKey(0, 2, 0), arm::pipe::CommandHandlerKey(0, 2, 1) };
105
106     BOOST_CHECK(vect == expectedVect);
107 }
108
109 BOOST_AUTO_TEST_CASE(CheckPacketKeyComparisons)
110 {
111     arm::pipe::PacketKey key0(0, 0);
112     arm::pipe::PacketKey key1(0, 0);
113     arm::pipe::PacketKey key2(0, 1);
114     arm::pipe::PacketKey key3(0, 2);
115     arm::pipe::PacketKey key4(1, 0);
116     arm::pipe::PacketKey key5(1, 0);
117     arm::pipe::PacketKey key6(1, 1);
118
119     BOOST_CHECK(!(key0 < key1));
120     BOOST_CHECK(!(key0 > key1));
121     BOOST_CHECK(key0 <= key1);
122     BOOST_CHECK(key0 >= key1);
123     BOOST_CHECK(key0 == key1);
124     BOOST_CHECK(key0 < key2);
125     BOOST_CHECK(key2 < key3);
126     BOOST_CHECK(key3 > key0);
127     BOOST_CHECK(key4 == key5);
128     BOOST_CHECK(key4 > key0);
129     BOOST_CHECK(key5 < key6);
130     BOOST_CHECK(key5 <= key6);
131     BOOST_CHECK(key5 != key6);
132 }
133
134 BOOST_AUTO_TEST_CASE(CheckCommandHandler)
135 {
136     arm::pipe::PacketVersionResolver packetVersionResolver;
137     ProfilingStateMachine profilingStateMachine;
138
139     TestProfilingConnectionBase testProfilingConnectionBase;
140     TestProfilingConnectionTimeoutError testProfilingConnectionTimeOutError;
141     TestProfilingConnectionArmnnError testProfilingConnectionArmnnError;
142     CounterDirectory counterDirectory;
143     MockBufferManager mockBuffer(1024);
144     SendCounterPacket sendCounterPacket(mockBuffer);
145     SendThread sendThread(profilingStateMachine, mockBuffer, sendCounterPacket);
146     SendTimelinePacket sendTimelinePacket(mockBuffer);
147     MockProfilingServiceStatus mockProfilingServiceStatus;
148
149     ConnectionAcknowledgedCommandHandler connectionAcknowledgedCommandHandler(0, 1, 4194304, counterDirectory,
150                                                                               sendCounterPacket, sendTimelinePacket,
151                                                                               profilingStateMachine,
152                                                                               mockProfilingServiceStatus);
153     arm::pipe::CommandHandlerRegistry commandHandlerRegistry;
154
155     commandHandlerRegistry.RegisterFunctor(&connectionAcknowledgedCommandHandler);
156
157     profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
158     profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
159
160     CommandHandler commandHandler0(1, true, commandHandlerRegistry, packetVersionResolver);
161
162     // This should start the command handler thread return the connection ack and put the profiling
163     // service into active state.
164     commandHandler0.Start(testProfilingConnectionBase);
165     // Try to start the send thread many times, it must only start once
166     commandHandler0.Start(testProfilingConnectionBase);
167
168     // This could take up to 20mSec but we'll check often.
169     for (int i = 0; i < 10; i++)
170     {
171         if (profilingStateMachine.GetCurrentState() == ProfilingState::Active)
172         {
173             break;
174         }
175         std::this_thread::sleep_for(std::chrono::milliseconds(2));
176     }
177
178     BOOST_CHECK(profilingStateMachine.GetCurrentState() == ProfilingState::Active);
179
180     // Close the thread again.
181     commandHandler0.Stop();
182
183     profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
184     profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
185
186     // In this test we'll simulate a timeout without a connection ack packet being received.
187     // Stop after timeout is set so we expect the command handler to stop almost immediately.
188     CommandHandler commandHandler1(1, true, commandHandlerRegistry, packetVersionResolver);
189
190     commandHandler1.Start(testProfilingConnectionTimeOutError);
191     // Wait until we know a timeout exception has been sent at least once.
192     for (int i = 0; i < 10; i++)
193     {
194         if (testProfilingConnectionTimeOutError.ReadCalledCount())
195         {
196             break;
197         }
198         std::this_thread::sleep_for(std::chrono::milliseconds(2));
199     }
200
201     // The command handler loop should have stopped after the timeout.
202     // wait for the timeout exception to be processed and the loop to break.
203     uint32_t timeout   = 50;
204     uint32_t timeSlept = 0;
205     while (commandHandler1.IsRunning())
206     {
207         if (timeSlept >= timeout)
208         {
209             BOOST_FAIL("Timeout: The command handler loop did not stop after the timeout");
210         }
211         std::this_thread::sleep_for(std::chrono::milliseconds(1));
212         timeSlept ++;
213     }
214
215     commandHandler1.Stop();
216     // The state machine should never have received the ack so will still be in WaitingForAck.
217     BOOST_CHECK(profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck);
218
219     // Now try sending a bad connection acknowledged packet
220     TestProfilingConnectionBadAckPacket testProfilingConnectionBadAckPacket;
221     commandHandler1.Start(testProfilingConnectionBadAckPacket);
222     commandHandler1.Stop();
223     // This should also not change the state machine
224     BOOST_CHECK(profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck);
225
226     // Disable stop after timeout and now commandHandler1 should persist after a timeout
227     commandHandler1.SetStopAfterTimeout(false);
228     // Restart the thread.
229     commandHandler1.Start(testProfilingConnectionTimeOutError);
230
231     // Wait for at the three timeouts and the ack to be sent.
232     for (int i = 0; i < 10; i++)
233     {
234         if (testProfilingConnectionTimeOutError.ReadCalledCount() > 3)
235         {
236             break;
237         }
238         std::this_thread::sleep_for(std::chrono::milliseconds(2));
239     }
240     commandHandler1.Stop();
241
242     // Even after the 3 exceptions the ack packet should have transitioned the command handler to active.
243     BOOST_CHECK(profilingStateMachine.GetCurrentState() == ProfilingState::Active);
244
245     // A command handler that gets exceptions other than timeouts should keep going.
246     CommandHandler commandHandler2(1, false, commandHandlerRegistry, packetVersionResolver);
247
248     commandHandler2.Start(testProfilingConnectionArmnnError);
249
250     // Wait for two exceptions to be thrown.
251     for (int i = 0; i < 10; i++)
252     {
253         if (testProfilingConnectionTimeOutError.ReadCalledCount() >= 2)
254         {
255             break;
256         }
257         std::this_thread::sleep_for(std::chrono::milliseconds(2));
258     }
259
260     BOOST_CHECK(commandHandler2.IsRunning());
261     commandHandler2.Stop();
262 }
263
264 BOOST_AUTO_TEST_CASE(CheckEncodeVersion)
265 {
266     arm::pipe::Version version1(12);
267
268     BOOST_CHECK(version1.GetMajor() == 0);
269     BOOST_CHECK(version1.GetMinor() == 0);
270     BOOST_CHECK(version1.GetPatch() == 12);
271
272     arm::pipe::Version version2(4108);
273
274     BOOST_CHECK(version2.GetMajor() == 0);
275     BOOST_CHECK(version2.GetMinor() == 1);
276     BOOST_CHECK(version2.GetPatch() == 12);
277
278     arm::pipe::Version version3(4198412);
279
280     BOOST_CHECK(version3.GetMajor() == 1);
281     BOOST_CHECK(version3.GetMinor() == 1);
282     BOOST_CHECK(version3.GetPatch() == 12);
283
284     arm::pipe::Version version4(0);
285
286     BOOST_CHECK(version4.GetMajor() == 0);
287     BOOST_CHECK(version4.GetMinor() == 0);
288     BOOST_CHECK(version4.GetPatch() == 0);
289
290     arm::pipe::Version version5(1, 0, 0);
291     BOOST_CHECK(version5.GetEncodedValue() == 4194304);
292 }
293
294 BOOST_AUTO_TEST_CASE(CheckPacketClass)
295 {
296     uint32_t length                              = 4;
297     std::unique_ptr<unsigned char[]> packetData0 = std::make_unique<unsigned char[]>(length);
298     std::unique_ptr<unsigned char[]> packetData1 = std::make_unique<unsigned char[]>(0);
299     std::unique_ptr<unsigned char[]> nullPacketData;
300
301     arm::pipe::Packet packetTest0(472580096, length, packetData0);
302
303     BOOST_CHECK(packetTest0.GetHeader() == 472580096);
304     BOOST_CHECK(packetTest0.GetPacketFamily() == 7);
305     BOOST_CHECK(packetTest0.GetPacketId() == 43);
306     BOOST_CHECK(packetTest0.GetLength() == length);
307     BOOST_CHECK(packetTest0.GetPacketType() == 3);
308     BOOST_CHECK(packetTest0.GetPacketClass() == 5);
309
310     BOOST_CHECK_THROW(arm::pipe::Packet packetTest1(472580096, 0, packetData1), arm::pipe::InvalidArgumentException);
311     BOOST_CHECK_NO_THROW(arm::pipe::Packet packetTest2(472580096, 0, nullPacketData));
312
313     arm::pipe::Packet packetTest3(472580096, 0, nullPacketData);
314     BOOST_CHECK(packetTest3.GetLength() == 0);
315     BOOST_CHECK(packetTest3.GetData() == nullptr);
316
317     const unsigned char* packetTest0Data = packetTest0.GetData();
318     arm::pipe::Packet packetTest4(std::move(packetTest0));
319
320     BOOST_CHECK(packetTest0.GetData() == nullptr);
321     BOOST_CHECK(packetTest4.GetData() == packetTest0Data);
322
323     BOOST_CHECK(packetTest4.GetHeader() == 472580096);
324     BOOST_CHECK(packetTest4.GetPacketFamily() == 7);
325     BOOST_CHECK(packetTest4.GetPacketId() == 43);
326     BOOST_CHECK(packetTest4.GetLength() == length);
327     BOOST_CHECK(packetTest4.GetPacketType() == 3);
328     BOOST_CHECK(packetTest4.GetPacketClass() == 5);
329 }
330
331 BOOST_AUTO_TEST_CASE(CheckCommandHandlerFunctor)
332 {
333     // Hard code the version as it will be the same during a single profiling session
334     uint32_t version = 1;
335
336     TestFunctorA testFunctorA(7, 461, version);
337     TestFunctorB testFunctorB(8, 963, version);
338     TestFunctorC testFunctorC(5, 983, version);
339
340     arm::pipe::CommandHandlerKey keyA(
341         testFunctorA.GetFamilyId(), testFunctorA.GetPacketId(), testFunctorA.GetVersion());
342     arm::pipe::CommandHandlerKey keyB(
343         testFunctorB.GetFamilyId(), testFunctorB.GetPacketId(), testFunctorB.GetVersion());
344     arm::pipe::CommandHandlerKey keyC(
345         testFunctorC.GetFamilyId(), testFunctorC.GetPacketId(), testFunctorC.GetVersion());
346
347     // Create the unwrapped map to simulate the Command Handler Registry
348     std::map<arm::pipe::CommandHandlerKey, arm::pipe::CommandHandlerFunctor*> registry;
349
350     registry.insert(std::make_pair(keyB, &testFunctorB));
351     registry.insert(std::make_pair(keyA, &testFunctorA));
352     registry.insert(std::make_pair(keyC, &testFunctorC));
353
354     // Check the order of the map is correct
355     auto it = registry.begin();
356     BOOST_CHECK(it->first == keyC);    // familyId == 5
357     it++;
358     BOOST_CHECK(it->first == keyA);    // familyId == 7
359     it++;
360     BOOST_CHECK(it->first == keyB);    // familyId == 8
361
362     std::unique_ptr<unsigned char[]> packetDataA;
363     std::unique_ptr<unsigned char[]> packetDataB;
364     std::unique_ptr<unsigned char[]> packetDataC;
365
366     arm::pipe::Packet packetA(500000000, 0, packetDataA);
367     arm::pipe::Packet packetB(600000000, 0, packetDataB);
368     arm::pipe::Packet packetC(400000000, 0, packetDataC);
369
370     // Check the correct operator of derived class is called
371     registry.at(arm::pipe::CommandHandlerKey(
372         packetA.GetPacketFamily(), packetA.GetPacketId(), version))->operator()(packetA);
373     BOOST_CHECK(testFunctorA.GetCount() == 1);
374     BOOST_CHECK(testFunctorB.GetCount() == 0);
375     BOOST_CHECK(testFunctorC.GetCount() == 0);
376
377     registry.at(arm::pipe::CommandHandlerKey(
378         packetB.GetPacketFamily(), packetB.GetPacketId(), version))->operator()(packetB);
379     BOOST_CHECK(testFunctorA.GetCount() == 1);
380     BOOST_CHECK(testFunctorB.GetCount() == 1);
381     BOOST_CHECK(testFunctorC.GetCount() == 0);
382
383     registry.at(arm::pipe::CommandHandlerKey(
384         packetC.GetPacketFamily(), packetC.GetPacketId(), version))->operator()(packetC);
385     BOOST_CHECK(testFunctorA.GetCount() == 1);
386     BOOST_CHECK(testFunctorB.GetCount() == 1);
387     BOOST_CHECK(testFunctorC.GetCount() == 1);
388 }
389
390 BOOST_AUTO_TEST_CASE(CheckCommandHandlerRegistry)
391 {
392     // Hard code the version as it will be the same during a single profiling session
393     uint32_t version = 1;
394
395     TestFunctorA testFunctorA(7, 461, version);
396     TestFunctorB testFunctorB(8, 963, version);
397     TestFunctorC testFunctorC(5, 983, version);
398
399     // Create the Command Handler Registry
400     arm::pipe::CommandHandlerRegistry registry;
401
402     // Register multiple different derived classes
403     registry.RegisterFunctor(&testFunctorA);
404     registry.RegisterFunctor(&testFunctorB);
405     registry.RegisterFunctor(&testFunctorC);
406
407     std::unique_ptr<unsigned char[]> packetDataA;
408     std::unique_ptr<unsigned char[]> packetDataB;
409     std::unique_ptr<unsigned char[]> packetDataC;
410
411     arm::pipe::Packet packetA(500000000, 0, packetDataA);
412     arm::pipe::Packet packetB(600000000, 0, packetDataB);
413     arm::pipe::Packet packetC(400000000, 0, packetDataC);
414
415     // Check the correct operator of derived class is called
416     registry.GetFunctor(packetA.GetPacketFamily(), packetA.GetPacketId(), version)->operator()(packetA);
417     BOOST_CHECK(testFunctorA.GetCount() == 1);
418     BOOST_CHECK(testFunctorB.GetCount() == 0);
419     BOOST_CHECK(testFunctorC.GetCount() == 0);
420
421     registry.GetFunctor(packetB.GetPacketFamily(), packetB.GetPacketId(), version)->operator()(packetB);
422     BOOST_CHECK(testFunctorA.GetCount() == 1);
423     BOOST_CHECK(testFunctorB.GetCount() == 1);
424     BOOST_CHECK(testFunctorC.GetCount() == 0);
425
426     registry.GetFunctor(packetC.GetPacketFamily(), packetC.GetPacketId(), version)->operator()(packetC);
427     BOOST_CHECK(testFunctorA.GetCount() == 1);
428     BOOST_CHECK(testFunctorB.GetCount() == 1);
429     BOOST_CHECK(testFunctorC.GetCount() == 1);
430
431     // Re-register an existing key with a new function
432     registry.RegisterFunctor(&testFunctorC, testFunctorA.GetFamilyId(), testFunctorA.GetPacketId(), version);
433     registry.GetFunctor(packetA.GetPacketFamily(), packetA.GetPacketId(), version)->operator()(packetC);
434     BOOST_CHECK(testFunctorA.GetCount() == 1);
435     BOOST_CHECK(testFunctorB.GetCount() == 1);
436     BOOST_CHECK(testFunctorC.GetCount() == 2);
437
438     // Check that non-existent key returns nullptr for its functor
439     BOOST_CHECK_THROW(registry.GetFunctor(0, 0, 0), arm::pipe::ProfilingException);
440 }
441
442 BOOST_AUTO_TEST_CASE(CheckPacketVersionResolver)
443 {
444     // Set up random number generator for generating packetId values
445     std::random_device device;
446     std::mt19937 generator(device());
447     std::uniform_int_distribution<uint32_t> distribution(std::numeric_limits<uint32_t>::min(),
448                                                          std::numeric_limits<uint32_t>::max());
449
450     // NOTE: Expected version is always 1.0.0, regardless of packetId
451     const arm::pipe::Version expectedVersion(1, 0, 0);
452
453     arm::pipe::PacketVersionResolver packetVersionResolver;
454
455     constexpr unsigned int numTests = 10u;
456
457     for (unsigned int i = 0u; i < numTests; ++i)
458     {
459         const uint32_t familyId = distribution(generator);
460         const uint32_t packetId = distribution(generator);
461         arm::pipe::Version resolvedVersion = packetVersionResolver.ResolvePacketVersion(familyId, packetId);
462
463         BOOST_TEST(resolvedVersion == expectedVersion);
464     }
465 }
466
467 void ProfilingCurrentStateThreadImpl(ProfilingStateMachine& states)
468 {
469     ProfilingState newState = ProfilingState::NotConnected;
470     states.GetCurrentState();
471     states.TransitionToState(newState);
472 }
473
474 BOOST_AUTO_TEST_CASE(CheckProfilingStateMachine)
475 {
476     ProfilingStateMachine profilingState1(ProfilingState::Uninitialised);
477     profilingState1.TransitionToState(ProfilingState::Uninitialised);
478     BOOST_CHECK(profilingState1.GetCurrentState() == ProfilingState::Uninitialised);
479
480     ProfilingStateMachine profilingState2(ProfilingState::Uninitialised);
481     profilingState2.TransitionToState(ProfilingState::NotConnected);
482     BOOST_CHECK(profilingState2.GetCurrentState() == ProfilingState::NotConnected);
483
484     ProfilingStateMachine profilingState3(ProfilingState::NotConnected);
485     profilingState3.TransitionToState(ProfilingState::NotConnected);
486     BOOST_CHECK(profilingState3.GetCurrentState() == ProfilingState::NotConnected);
487
488     ProfilingStateMachine profilingState4(ProfilingState::NotConnected);
489     profilingState4.TransitionToState(ProfilingState::WaitingForAck);
490     BOOST_CHECK(profilingState4.GetCurrentState() == ProfilingState::WaitingForAck);
491
492     ProfilingStateMachine profilingState5(ProfilingState::WaitingForAck);
493     profilingState5.TransitionToState(ProfilingState::WaitingForAck);
494     BOOST_CHECK(profilingState5.GetCurrentState() == ProfilingState::WaitingForAck);
495
496     ProfilingStateMachine profilingState6(ProfilingState::WaitingForAck);
497     profilingState6.TransitionToState(ProfilingState::Active);
498     BOOST_CHECK(profilingState6.GetCurrentState() == ProfilingState::Active);
499
500     ProfilingStateMachine profilingState7(ProfilingState::Active);
501     profilingState7.TransitionToState(ProfilingState::NotConnected);
502     BOOST_CHECK(profilingState7.GetCurrentState() == ProfilingState::NotConnected);
503
504     ProfilingStateMachine profilingState8(ProfilingState::Active);
505     profilingState8.TransitionToState(ProfilingState::Active);
506     BOOST_CHECK(profilingState8.GetCurrentState() == ProfilingState::Active);
507
508     ProfilingStateMachine profilingState9(ProfilingState::Uninitialised);
509     BOOST_CHECK_THROW(profilingState9.TransitionToState(ProfilingState::WaitingForAck), armnn::Exception);
510
511     ProfilingStateMachine profilingState10(ProfilingState::Uninitialised);
512     BOOST_CHECK_THROW(profilingState10.TransitionToState(ProfilingState::Active), armnn::Exception);
513
514     ProfilingStateMachine profilingState11(ProfilingState::NotConnected);
515     BOOST_CHECK_THROW(profilingState11.TransitionToState(ProfilingState::Uninitialised), armnn::Exception);
516
517     ProfilingStateMachine profilingState12(ProfilingState::NotConnected);
518     BOOST_CHECK_THROW(profilingState12.TransitionToState(ProfilingState::Active), armnn::Exception);
519
520     ProfilingStateMachine profilingState13(ProfilingState::WaitingForAck);
521     BOOST_CHECK_THROW(profilingState13.TransitionToState(ProfilingState::Uninitialised), armnn::Exception);
522
523     ProfilingStateMachine profilingState14(ProfilingState::WaitingForAck);
524     profilingState14.TransitionToState(ProfilingState::NotConnected);
525     BOOST_CHECK(profilingState14.GetCurrentState() == ProfilingState::NotConnected);
526
527     ProfilingStateMachine profilingState15(ProfilingState::Active);
528     BOOST_CHECK_THROW(profilingState15.TransitionToState(ProfilingState::Uninitialised), armnn::Exception);
529
530     ProfilingStateMachine profilingState16(armnn::profiling::ProfilingState::Active);
531     BOOST_CHECK_THROW(profilingState16.TransitionToState(ProfilingState::WaitingForAck), armnn::Exception);
532
533     ProfilingStateMachine profilingState17(ProfilingState::Uninitialised);
534
535     std::thread thread1(ProfilingCurrentStateThreadImpl, std::ref(profilingState17));
536     std::thread thread2(ProfilingCurrentStateThreadImpl, std::ref(profilingState17));
537     std::thread thread3(ProfilingCurrentStateThreadImpl, std::ref(profilingState17));
538     std::thread thread4(ProfilingCurrentStateThreadImpl, std::ref(profilingState17));
539     std::thread thread5(ProfilingCurrentStateThreadImpl, std::ref(profilingState17));
540
541     thread1.join();
542     thread2.join();
543     thread3.join();
544     thread4.join();
545     thread5.join();
546
547     BOOST_TEST((profilingState17.GetCurrentState() == ProfilingState::NotConnected));
548 }
549
550 void CaptureDataWriteThreadImpl(Holder& holder, uint32_t capturePeriod, const std::vector<uint16_t>& counterIds)
551 {
552     holder.SetCaptureData(capturePeriod, counterIds, {});
553 }
554
555 void CaptureDataReadThreadImpl(const Holder& holder, CaptureData& captureData)
556 {
557     captureData = holder.GetCaptureData();
558 }
559
560 BOOST_AUTO_TEST_CASE(CheckCaptureDataHolder)
561 {
562     std::map<uint32_t, std::vector<uint16_t>> periodIdMap;
563     std::vector<uint16_t> counterIds;
564     uint32_t numThreads = 10;
565     for (uint32_t i = 0; i < numThreads; ++i)
566     {
567         counterIds.emplace_back(i);
568         periodIdMap.insert(std::make_pair(i, counterIds));
569     }
570
571     // Verify the read and write threads set the holder correctly
572     // and retrieve the expected values
573     Holder holder;
574     BOOST_CHECK((holder.GetCaptureData()).GetCapturePeriod() == 0);
575     BOOST_CHECK(((holder.GetCaptureData()).GetCounterIds()).empty());
576
577     // Check Holder functions
578     std::thread thread1(CaptureDataWriteThreadImpl, std::ref(holder), 2, std::ref(periodIdMap[2]));
579     thread1.join();
580     BOOST_CHECK((holder.GetCaptureData()).GetCapturePeriod() == 2);
581     BOOST_CHECK((holder.GetCaptureData()).GetCounterIds() == periodIdMap[2]);
582     // NOTE: now that we have some initial values in the holder we don't have to worry
583     //       in the multi-threaded section below about a read thread accessing the holder
584     //       before any write thread has gotten to it so we read period = 0, counterIds empty
585     //       instead of period = 0, counterIds = {0} as will the case when write thread 0
586     //       has executed.
587
588     CaptureData captureData;
589     std::thread thread2(CaptureDataReadThreadImpl, std::ref(holder), std::ref(captureData));
590     thread2.join();
591     BOOST_CHECK(captureData.GetCapturePeriod() == 2);
592     BOOST_CHECK(captureData.GetCounterIds() == periodIdMap[2]);
593
594     std::map<uint32_t, CaptureData> captureDataIdMap;
595     for (uint32_t i = 0; i < numThreads; ++i)
596     {
597         CaptureData perThreadCaptureData;
598         captureDataIdMap.insert(std::make_pair(i, perThreadCaptureData));
599     }
600
601     std::vector<std::thread> threadsVect;
602     std::vector<std::thread> readThreadsVect;
603     for (uint32_t i = 0; i < numThreads; ++i)
604     {
605         threadsVect.emplace_back(
606             std::thread(CaptureDataWriteThreadImpl, std::ref(holder), i, std::ref(periodIdMap[i])));
607
608         // Verify that the CaptureData goes into the thread in a virgin state
609         BOOST_CHECK(captureDataIdMap.at(i).GetCapturePeriod() == 0);
610         BOOST_CHECK(captureDataIdMap.at(i).GetCounterIds().empty());
611         readThreadsVect.emplace_back(
612             std::thread(CaptureDataReadThreadImpl, std::ref(holder), std::ref(captureDataIdMap.at(i))));
613     }
614
615     for (uint32_t i = 0; i < numThreads; ++i)
616     {
617         threadsVect[i].join();
618         readThreadsVect[i].join();
619     }
620
621     // Look at the CaptureData that each read thread has filled
622     // the capture period it read should match the counter ids entry
623     for (uint32_t i = 0; i < numThreads; ++i)
624     {
625         CaptureData perThreadCaptureData = captureDataIdMap.at(i);
626         BOOST_CHECK(perThreadCaptureData.GetCounterIds() == periodIdMap.at(perThreadCaptureData.GetCapturePeriod()));
627     }
628 }
629
630 BOOST_AUTO_TEST_CASE(CaptureDataMethods)
631 {
632     // Check CaptureData setter and getter functions
633     std::vector<uint16_t> counterIds = { 42, 29, 13 };
634     CaptureData captureData;
635     BOOST_CHECK(captureData.GetCapturePeriod() == 0);
636     BOOST_CHECK((captureData.GetCounterIds()).empty());
637     captureData.SetCapturePeriod(150);
638     captureData.SetCounterIds(counterIds);
639     BOOST_CHECK(captureData.GetCapturePeriod() == 150);
640     BOOST_CHECK(captureData.GetCounterIds() == counterIds);
641
642     // Check assignment operator
643     CaptureData secondCaptureData;
644
645     secondCaptureData = captureData;
646     BOOST_CHECK(secondCaptureData.GetCapturePeriod() == 150);
647     BOOST_CHECK(secondCaptureData.GetCounterIds() == counterIds);
648
649     // Check copy constructor
650     CaptureData copyConstructedCaptureData(captureData);
651
652     BOOST_CHECK(copyConstructedCaptureData.GetCapturePeriod() == 150);
653     BOOST_CHECK(copyConstructedCaptureData.GetCounterIds() == counterIds);
654 }
655
656 BOOST_AUTO_TEST_CASE(CheckProfilingServiceDisabled)
657 {
658     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
659     armnn::profiling::ProfilingService profilingService;
660     profilingService.ResetExternalProfilingOptions(options, true);
661     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
662     profilingService.Update();
663     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
664 }
665
666 BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterDirectory)
667 {
668     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
669     armnn::profiling::ProfilingService profilingService;
670     profilingService.ResetExternalProfilingOptions(options, true);
671
672     const ICounterDirectory& counterDirectory0 = profilingService.GetCounterDirectory();
673     BOOST_CHECK(counterDirectory0.GetCounterCount() == 0);
674     profilingService.Update();
675     BOOST_CHECK(counterDirectory0.GetCounterCount() == 0);
676
677     options.m_EnableProfiling = true;
678     profilingService.ResetExternalProfilingOptions(options);
679
680     const ICounterDirectory& counterDirectory1 = profilingService.GetCounterDirectory();
681     BOOST_CHECK(counterDirectory1.GetCounterCount() == 0);
682     profilingService.Update();
683     BOOST_CHECK(counterDirectory1.GetCounterCount() != 0);
684     // Reset the profiling service to stop any running thread
685     options.m_EnableProfiling = false;
686     profilingService.ResetExternalProfilingOptions(options, true);
687 }
688
689 BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterValues)
690 {
691     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
692     options.m_EnableProfiling          = true;
693     armnn::profiling::ProfilingService profilingService;
694     profilingService.ResetExternalProfilingOptions(options, true);
695
696     profilingService.Update();
697     const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
698     const Counters& counters                  = counterDirectory.GetCounters();
699     BOOST_CHECK(!counters.empty());
700
701     std::vector<std::thread> writers;
702
703     BOOST_CHECK(!counters.empty());
704
705     // Test GetAbsoluteCounterValue
706     for (int i = 0; i < 4; ++i)
707     {
708         // Increment and decrement the INFERENCES_RUN counter 250 times
709         writers.push_back(std::thread([&profilingService]()
710                                       {
711                                           for (int i = 0; i < 250; ++i)
712                                           {
713                                               profilingService.IncrementCounterValue(INFERENCES_RUN);
714                                           }
715                                       }));
716         // Add 10 to the INFERENCES_RUN counter 200 times
717         writers.push_back(std::thread([&profilingService]()
718                                       {
719                                           for (int i = 0; i < 200; ++i)
720                                           {
721                                               profilingService.AddCounterValue(INFERENCES_RUN, 10);
722                                           }
723                                       }));
724         // Subtract 5 from the INFERENCES_RUN counter 200 times
725         writers.push_back(std::thread([&profilingService]()
726                                       {
727                                           for (int i = 0; i < 200; ++i)
728                                           {
729                                               profilingService.SubtractCounterValue(INFERENCES_RUN, 5);
730                                           }
731                                       }));
732     }
733
734     std::for_each(writers.begin(), writers.end(), mem_fn(&std::thread::join));
735
736     uint32_t absoluteCounterValue = 0;
737
738     BOOST_CHECK_NO_THROW(absoluteCounterValue = profilingService.GetAbsoluteCounterValue(INFERENCES_RUN));
739     BOOST_CHECK(absoluteCounterValue = 5000);
740
741     // Test SetCounterValue
742     BOOST_CHECK_NO_THROW(profilingService.SetCounterValue(INFERENCES_RUN, 0));
743     BOOST_CHECK_NO_THROW(absoluteCounterValue = profilingService.GetAbsoluteCounterValue(INFERENCES_RUN));
744     BOOST_CHECK(absoluteCounterValue == 0);
745
746     // Test GetDeltaCounterValue
747     writers.clear();
748     uint32_t deltaCounterValue = 0;
749     //Start a reading thread to randomly read the INFERENCES_RUN counter value
750     std::thread reader([&profilingService](uint32_t& deltaCounterValue)
751                        {
752                            for (int i = 0; i < 300; ++i)
753                            {
754                                deltaCounterValue += profilingService.GetDeltaCounterValue(INFERENCES_RUN);
755                            }
756                        }, std::ref(deltaCounterValue));
757
758     for (int i = 0; i < 4; ++i)
759     {
760         // Increment and decrement the INFERENCES_RUN counter 250 times
761         writers.push_back(std::thread([&profilingService]()
762                                       {
763                                           for (int i = 0; i < 250; ++i)
764                                           {
765                                               profilingService.IncrementCounterValue(INFERENCES_RUN);
766                                           }
767                                       }));
768         // Add 10 to the INFERENCES_RUN counter 200 times
769         writers.push_back(std::thread([&profilingService]()
770                                       {
771                                           for (int i = 0; i < 200; ++i)
772                                           {
773                                               profilingService.AddCounterValue(INFERENCES_RUN, 10);
774                                           }
775                                       }));
776         // Subtract 5 from the INFERENCES_RUN counter 200 times
777         writers.push_back(std::thread([&profilingService]()
778                                       {
779                                           for (int i = 0; i < 200; ++i)
780                                           {
781                                               profilingService.SubtractCounterValue(INFERENCES_RUN, 5);
782                                           }
783                                       }));
784     }
785
786     std::for_each(writers.begin(), writers.end(), mem_fn(&std::thread::join));
787     reader.join();
788
789     // Do one last read in case the reader stopped early
790     deltaCounterValue += profilingService.GetDeltaCounterValue(INFERENCES_RUN);
791     BOOST_CHECK(deltaCounterValue == 5000);
792
793     // Reset the profiling service to stop any running thread
794     options.m_EnableProfiling = false;
795     profilingService.ResetExternalProfilingOptions(options, true);
796 }
797
798 BOOST_AUTO_TEST_CASE(CheckProfilingObjectUids)
799 {
800     uint16_t uid = 0;
801     BOOST_CHECK_NO_THROW(uid = GetNextUid());
802     BOOST_CHECK(uid >= 1);
803
804     uint16_t nextUid = 0;
805     BOOST_CHECK_NO_THROW(nextUid = GetNextUid());
806     BOOST_CHECK(nextUid > uid);
807
808     std::vector<uint16_t> counterUids;
809     BOOST_CHECK_NO_THROW(counterUids = GetNextCounterUids(uid,0));
810     BOOST_CHECK(counterUids.size() == 1);
811
812     std::vector<uint16_t> nextCounterUids;
813     BOOST_CHECK_NO_THROW(nextCounterUids = GetNextCounterUids(nextUid, 2));
814     BOOST_CHECK(nextCounterUids.size() == 2);
815     BOOST_CHECK(nextCounterUids[0] > counterUids[0]);
816
817     std::vector<uint16_t> counterUidsMultiCore;
818     uint16_t thirdUid = 4;
819     uint16_t numberOfCores = 13;
820     BOOST_CHECK_NO_THROW(counterUidsMultiCore = GetNextCounterUids(thirdUid, numberOfCores));
821     BOOST_CHECK(counterUidsMultiCore.size() == numberOfCores);
822     BOOST_CHECK(counterUidsMultiCore.front() >= nextCounterUids[0]);
823     for (size_t i = 1; i < numberOfCores; i++)
824     {
825         BOOST_CHECK(counterUidsMultiCore[i] == counterUidsMultiCore[i - 1] + 1);
826     }
827     BOOST_CHECK(counterUidsMultiCore.back() == counterUidsMultiCore.front() + numberOfCores - 1);
828 }
829
830 BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterCategory)
831 {
832     CounterDirectory counterDirectory;
833     BOOST_CHECK(counterDirectory.GetCategoryCount() == 0);
834     BOOST_CHECK(counterDirectory.GetDeviceCount() == 0);
835     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0);
836     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
837
838     // Register a category with an invalid name
839     const Category* noCategory = nullptr;
840     BOOST_CHECK_THROW(noCategory = counterDirectory.RegisterCategory(""), armnn::InvalidArgumentException);
841     BOOST_CHECK(counterDirectory.GetCategoryCount() == 0);
842     BOOST_CHECK(!noCategory);
843
844     // Register a category with an invalid name
845     BOOST_CHECK_THROW(noCategory = counterDirectory.RegisterCategory("invalid category"),
846                       armnn::InvalidArgumentException);
847     BOOST_CHECK(counterDirectory.GetCategoryCount() == 0);
848     BOOST_CHECK(!noCategory);
849
850     // Register a new category
851     const std::string categoryName = "some_category";
852     const Category* category       = nullptr;
853     BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName));
854     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
855     BOOST_CHECK(category);
856     BOOST_CHECK(category->m_Name == categoryName);
857     BOOST_CHECK(category->m_Counters.empty());
858
859     // Get the registered category
860     const Category* registeredCategory = counterDirectory.GetCategory(categoryName);
861     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
862     BOOST_CHECK(registeredCategory);
863     BOOST_CHECK(registeredCategory == category);
864
865     // Try to get a category not registered
866     const Category* notRegisteredCategory = counterDirectory.GetCategory("not_registered_category");
867     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
868     BOOST_CHECK(!notRegisteredCategory);
869
870     // Register a category already registered
871     const Category* anotherCategory = nullptr;
872     BOOST_CHECK_THROW(anotherCategory = counterDirectory.RegisterCategory(categoryName),
873                       armnn::InvalidArgumentException);
874     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
875     BOOST_CHECK(!anotherCategory);
876
877     // Register a device for testing
878     const std::string deviceName = "some_device";
879     const Device* device         = nullptr;
880     BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName));
881     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
882     BOOST_CHECK(device);
883     BOOST_CHECK(device->m_Uid >= 1);
884     BOOST_CHECK(device->m_Name == deviceName);
885     BOOST_CHECK(device->m_Cores == 0);
886
887     // Register a new category not associated to any device
888     const std::string categoryWoDeviceName = "some_category_without_device";
889     const Category* categoryWoDevice       = nullptr;
890     BOOST_CHECK_NO_THROW(categoryWoDevice = counterDirectory.RegisterCategory(categoryWoDeviceName));
891     BOOST_CHECK(counterDirectory.GetCategoryCount() == 2);
892     BOOST_CHECK(categoryWoDevice);
893     BOOST_CHECK(categoryWoDevice->m_Name == categoryWoDeviceName);
894     BOOST_CHECK(categoryWoDevice->m_Counters.empty());
895
896     // Register a new category associated to an invalid device name (already exist)
897     const Category* categoryInvalidDeviceName = nullptr;
898     BOOST_CHECK_THROW(categoryInvalidDeviceName =
899                           counterDirectory.RegisterCategory(categoryWoDeviceName),
900                       armnn::InvalidArgumentException);
901     BOOST_CHECK(counterDirectory.GetCategoryCount() == 2);
902     BOOST_CHECK(!categoryInvalidDeviceName);
903
904     // Register a new category associated to a valid device
905     const std::string categoryWValidDeviceName = "some_category_with_valid_device";
906     const Category* categoryWValidDevice       = nullptr;
907     BOOST_CHECK_NO_THROW(categoryWValidDevice =
908                              counterDirectory.RegisterCategory(categoryWValidDeviceName));
909     BOOST_CHECK(counterDirectory.GetCategoryCount() == 3);
910     BOOST_CHECK(categoryWValidDevice);
911     BOOST_CHECK(categoryWValidDevice != category);
912     BOOST_CHECK(categoryWValidDevice->m_Name == categoryWValidDeviceName);
913
914     // Register a counter set for testing
915     const std::string counterSetName = "some_counter_set";
916     const CounterSet* counterSet     = nullptr;
917     BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
918     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
919     BOOST_CHECK(counterSet);
920     BOOST_CHECK(counterSet->m_Uid >= 1);
921     BOOST_CHECK(counterSet->m_Name == counterSetName);
922     BOOST_CHECK(counterSet->m_Count == 0);
923
924     // Register a new category not associated to any counter set
925     const std::string categoryWoCounterSetName = "some_category_without_counter_set";
926     const Category* categoryWoCounterSet       = nullptr;
927     BOOST_CHECK_NO_THROW(categoryWoCounterSet =
928                              counterDirectory.RegisterCategory(categoryWoCounterSetName));
929     BOOST_CHECK(counterDirectory.GetCategoryCount() == 4);
930     BOOST_CHECK(categoryWoCounterSet);
931     BOOST_CHECK(categoryWoCounterSet->m_Name == categoryWoCounterSetName);
932
933     // Register a new category associated to a valid counter set
934     const std::string categoryWValidCounterSetName = "some_category_with_valid_counter_set";
935     const Category* categoryWValidCounterSet       = nullptr;
936     BOOST_CHECK_NO_THROW(categoryWValidCounterSet = counterDirectory.RegisterCategory(categoryWValidCounterSetName));
937     BOOST_CHECK(counterDirectory.GetCategoryCount() == 5);
938     BOOST_CHECK(categoryWValidCounterSet);
939     BOOST_CHECK(categoryWValidCounterSet != category);
940     BOOST_CHECK(categoryWValidCounterSet->m_Name == categoryWValidCounterSetName);
941
942     // Register a new category associated to a valid device and counter set
943     const std::string categoryWValidDeviceAndValidCounterSetName = "some_category_with_valid_device_and_counter_set";
944     const Category* categoryWValidDeviceAndValidCounterSet       = nullptr;
945     BOOST_CHECK_NO_THROW(categoryWValidDeviceAndValidCounterSet = counterDirectory.RegisterCategory(
946                              categoryWValidDeviceAndValidCounterSetName));
947     BOOST_CHECK(counterDirectory.GetCategoryCount() == 6);
948     BOOST_CHECK(categoryWValidDeviceAndValidCounterSet);
949     BOOST_CHECK(categoryWValidDeviceAndValidCounterSet != category);
950     BOOST_CHECK(categoryWValidDeviceAndValidCounterSet->m_Name == categoryWValidDeviceAndValidCounterSetName);
951 }
952
953 BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterDevice)
954 {
955     CounterDirectory counterDirectory;
956     BOOST_CHECK(counterDirectory.GetCategoryCount() == 0);
957     BOOST_CHECK(counterDirectory.GetDeviceCount() == 0);
958     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0);
959     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
960
961     // Register a device with an invalid name
962     const Device* noDevice = nullptr;
963     BOOST_CHECK_THROW(noDevice = counterDirectory.RegisterDevice(""), armnn::InvalidArgumentException);
964     BOOST_CHECK(counterDirectory.GetDeviceCount() == 0);
965     BOOST_CHECK(!noDevice);
966
967     // Register a device with an invalid name
968     BOOST_CHECK_THROW(noDevice = counterDirectory.RegisterDevice("inv@lid nam€"), armnn::InvalidArgumentException);
969     BOOST_CHECK(counterDirectory.GetDeviceCount() == 0);
970     BOOST_CHECK(!noDevice);
971
972     // Register a new device with no cores or parent category
973     const std::string deviceName = "some_device";
974     const Device* device         = nullptr;
975     BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName));
976     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
977     BOOST_CHECK(device);
978     BOOST_CHECK(device->m_Name == deviceName);
979     BOOST_CHECK(device->m_Uid >= 1);
980     BOOST_CHECK(device->m_Cores == 0);
981
982     // Try getting an unregistered device
983     const Device* unregisteredDevice = counterDirectory.GetDevice(9999);
984     BOOST_CHECK(!unregisteredDevice);
985
986     // Get the registered device
987     const Device* registeredDevice = counterDirectory.GetDevice(device->m_Uid);
988     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
989     BOOST_CHECK(registeredDevice);
990     BOOST_CHECK(registeredDevice == device);
991
992     // Register a device with the name of a device already registered
993     const Device* deviceSameName = nullptr;
994     BOOST_CHECK_THROW(deviceSameName = counterDirectory.RegisterDevice(deviceName), armnn::InvalidArgumentException);
995     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
996     BOOST_CHECK(!deviceSameName);
997
998     // Register a new device with cores and no parent category
999     const std::string deviceWCoresName = "some_device_with_cores";
1000     const Device* deviceWCores         = nullptr;
1001     BOOST_CHECK_NO_THROW(deviceWCores = counterDirectory.RegisterDevice(deviceWCoresName, 2));
1002     BOOST_CHECK(counterDirectory.GetDeviceCount() == 2);
1003     BOOST_CHECK(deviceWCores);
1004     BOOST_CHECK(deviceWCores->m_Name == deviceWCoresName);
1005     BOOST_CHECK(deviceWCores->m_Uid >= 1);
1006     BOOST_CHECK(deviceWCores->m_Uid > device->m_Uid);
1007     BOOST_CHECK(deviceWCores->m_Cores == 2);
1008
1009     // Get the registered device
1010     const Device* registeredDeviceWCores = counterDirectory.GetDevice(deviceWCores->m_Uid);
1011     BOOST_CHECK(counterDirectory.GetDeviceCount() == 2);
1012     BOOST_CHECK(registeredDeviceWCores);
1013     BOOST_CHECK(registeredDeviceWCores == deviceWCores);
1014     BOOST_CHECK(registeredDeviceWCores != device);
1015
1016     // Register a new device with cores and invalid parent category
1017     const std::string deviceWCoresWInvalidParentCategoryName = "some_device_with_cores_with_invalid_parent_category";
1018     const Device* deviceWCoresWInvalidParentCategory         = nullptr;
1019     BOOST_CHECK_THROW(deviceWCoresWInvalidParentCategory =
1020                           counterDirectory.RegisterDevice(deviceWCoresWInvalidParentCategoryName, 3, std::string("")),
1021                       armnn::InvalidArgumentException);
1022     BOOST_CHECK(counterDirectory.GetDeviceCount() == 2);
1023     BOOST_CHECK(!deviceWCoresWInvalidParentCategory);
1024
1025     // Register a new device with cores and invalid parent category
1026     const std::string deviceWCoresWInvalidParentCategoryName2 = "some_device_with_cores_with_invalid_parent_category2";
1027     const Device* deviceWCoresWInvalidParentCategory2         = nullptr;
1028     BOOST_CHECK_THROW(deviceWCoresWInvalidParentCategory2 = counterDirectory.RegisterDevice(
1029                           deviceWCoresWInvalidParentCategoryName2, 3, std::string("invalid_parent_category")),
1030                       armnn::InvalidArgumentException);
1031     BOOST_CHECK(counterDirectory.GetDeviceCount() == 2);
1032     BOOST_CHECK(!deviceWCoresWInvalidParentCategory2);
1033
1034     // Register a category for testing
1035     const std::string categoryName = "some_category";
1036     const Category* category       = nullptr;
1037     BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName));
1038     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
1039     BOOST_CHECK(category);
1040     BOOST_CHECK(category->m_Name == categoryName);
1041     BOOST_CHECK(category->m_Counters.empty());
1042
1043     // Register a new device with cores and valid parent category
1044     const std::string deviceWCoresWValidParentCategoryName = "some_device_with_cores_with_valid_parent_category";
1045     const Device* deviceWCoresWValidParentCategory         = nullptr;
1046     BOOST_CHECK_NO_THROW(deviceWCoresWValidParentCategory =
1047                              counterDirectory.RegisterDevice(deviceWCoresWValidParentCategoryName, 4, categoryName));
1048     BOOST_CHECK(counterDirectory.GetDeviceCount() == 3);
1049     BOOST_CHECK(deviceWCoresWValidParentCategory);
1050     BOOST_CHECK(deviceWCoresWValidParentCategory->m_Name == deviceWCoresWValidParentCategoryName);
1051     BOOST_CHECK(deviceWCoresWValidParentCategory->m_Uid >= 1);
1052     BOOST_CHECK(deviceWCoresWValidParentCategory->m_Uid > device->m_Uid);
1053     BOOST_CHECK(deviceWCoresWValidParentCategory->m_Uid > deviceWCores->m_Uid);
1054     BOOST_CHECK(deviceWCoresWValidParentCategory->m_Cores == 4);
1055 }
1056
1057 BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterCounterSet)
1058 {
1059     CounterDirectory counterDirectory;
1060     BOOST_CHECK(counterDirectory.GetCategoryCount() == 0);
1061     BOOST_CHECK(counterDirectory.GetDeviceCount() == 0);
1062     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0);
1063     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1064
1065     // Register a counter set with an invalid name
1066     const CounterSet* noCounterSet = nullptr;
1067     BOOST_CHECK_THROW(noCounterSet = counterDirectory.RegisterCounterSet(""), armnn::InvalidArgumentException);
1068     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0);
1069     BOOST_CHECK(!noCounterSet);
1070
1071     // Register a counter set with an invalid name
1072     BOOST_CHECK_THROW(noCounterSet = counterDirectory.RegisterCounterSet("invalid name"),
1073                       armnn::InvalidArgumentException);
1074     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0);
1075     BOOST_CHECK(!noCounterSet);
1076
1077     // Register a new counter set with no count or parent category
1078     const std::string counterSetName = "some_counter_set";
1079     const CounterSet* counterSet     = nullptr;
1080     BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1081     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1082     BOOST_CHECK(counterSet);
1083     BOOST_CHECK(counterSet->m_Name == counterSetName);
1084     BOOST_CHECK(counterSet->m_Uid >= 1);
1085     BOOST_CHECK(counterSet->m_Count == 0);
1086
1087     // Try getting an unregistered counter set
1088     const CounterSet* unregisteredCounterSet = counterDirectory.GetCounterSet(9999);
1089     BOOST_CHECK(!unregisteredCounterSet);
1090
1091     // Get the registered counter set
1092     const CounterSet* registeredCounterSet = counterDirectory.GetCounterSet(counterSet->m_Uid);
1093     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1094     BOOST_CHECK(registeredCounterSet);
1095     BOOST_CHECK(registeredCounterSet == counterSet);
1096
1097     // Register a counter set with the name of a counter set already registered
1098     const CounterSet* counterSetSameName = nullptr;
1099     BOOST_CHECK_THROW(counterSetSameName = counterDirectory.RegisterCounterSet(counterSetName),
1100                       armnn::InvalidArgumentException);
1101     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1102     BOOST_CHECK(!counterSetSameName);
1103
1104     // Register a new counter set with count and no parent category
1105     const std::string counterSetWCountName = "some_counter_set_with_count";
1106     const CounterSet* counterSetWCount     = nullptr;
1107     BOOST_CHECK_NO_THROW(counterSetWCount = counterDirectory.RegisterCounterSet(counterSetWCountName, 37));
1108     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2);
1109     BOOST_CHECK(counterSetWCount);
1110     BOOST_CHECK(counterSetWCount->m_Name == counterSetWCountName);
1111     BOOST_CHECK(counterSetWCount->m_Uid >= 1);
1112     BOOST_CHECK(counterSetWCount->m_Uid > counterSet->m_Uid);
1113     BOOST_CHECK(counterSetWCount->m_Count == 37);
1114
1115     // Get the registered counter set
1116     const CounterSet* registeredCounterSetWCount = counterDirectory.GetCounterSet(counterSetWCount->m_Uid);
1117     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2);
1118     BOOST_CHECK(registeredCounterSetWCount);
1119     BOOST_CHECK(registeredCounterSetWCount == counterSetWCount);
1120     BOOST_CHECK(registeredCounterSetWCount != counterSet);
1121
1122     // Register a new counter set with count and invalid parent category
1123     const std::string counterSetWCountWInvalidParentCategoryName = "some_counter_set_with_count_"
1124                                                                    "with_invalid_parent_category";
1125     const CounterSet* counterSetWCountWInvalidParentCategory = nullptr;
1126     BOOST_CHECK_THROW(counterSetWCountWInvalidParentCategory = counterDirectory.RegisterCounterSet(
1127                           counterSetWCountWInvalidParentCategoryName, 42, std::string("")),
1128                       armnn::InvalidArgumentException);
1129     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2);
1130     BOOST_CHECK(!counterSetWCountWInvalidParentCategory);
1131
1132     // Register a new counter set with count and invalid parent category
1133     const std::string counterSetWCountWInvalidParentCategoryName2 = "some_counter_set_with_count_"
1134                                                                     "with_invalid_parent_category2";
1135     const CounterSet* counterSetWCountWInvalidParentCategory2 = nullptr;
1136     BOOST_CHECK_THROW(counterSetWCountWInvalidParentCategory2 = counterDirectory.RegisterCounterSet(
1137                           counterSetWCountWInvalidParentCategoryName2, 42, std::string("invalid_parent_category")),
1138                       armnn::InvalidArgumentException);
1139     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2);
1140     BOOST_CHECK(!counterSetWCountWInvalidParentCategory2);
1141
1142     // Register a category for testing
1143     const std::string categoryName = "some_category";
1144     const Category* category       = nullptr;
1145     BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName));
1146     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
1147     BOOST_CHECK(category);
1148     BOOST_CHECK(category->m_Name == categoryName);
1149     BOOST_CHECK(category->m_Counters.empty());
1150
1151     // Register a new counter set with count and valid parent category
1152     const std::string counterSetWCountWValidParentCategoryName = "some_counter_set_with_count_"
1153                                                                  "with_valid_parent_category";
1154     const CounterSet* counterSetWCountWValidParentCategory = nullptr;
1155     BOOST_CHECK_NO_THROW(counterSetWCountWValidParentCategory = counterDirectory.RegisterCounterSet(
1156                              counterSetWCountWValidParentCategoryName, 42, categoryName));
1157     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 3);
1158     BOOST_CHECK(counterSetWCountWValidParentCategory);
1159     BOOST_CHECK(counterSetWCountWValidParentCategory->m_Name == counterSetWCountWValidParentCategoryName);
1160     BOOST_CHECK(counterSetWCountWValidParentCategory->m_Uid >= 1);
1161     BOOST_CHECK(counterSetWCountWValidParentCategory->m_Uid > counterSet->m_Uid);
1162     BOOST_CHECK(counterSetWCountWValidParentCategory->m_Uid > counterSetWCount->m_Uid);
1163     BOOST_CHECK(counterSetWCountWValidParentCategory->m_Count == 42);
1164
1165     // Register a counter set associated to a category with invalid name
1166     const std::string counterSetSameCategoryName = "some_counter_set_with_invalid_parent_category";
1167     const std::string invalidCategoryName = "";
1168     const CounterSet* counterSetSameCategory     = nullptr;
1169     BOOST_CHECK_THROW(counterSetSameCategory =
1170                           counterDirectory.RegisterCounterSet(counterSetSameCategoryName, 0, invalidCategoryName),
1171                       armnn::InvalidArgumentException);
1172     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 3);
1173     BOOST_CHECK(!counterSetSameCategory);
1174 }
1175
1176 BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterCounter)
1177 {
1178     CounterDirectory counterDirectory;
1179     BOOST_CHECK(counterDirectory.GetCategoryCount() == 0);
1180     BOOST_CHECK(counterDirectory.GetDeviceCount() == 0);
1181     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0);
1182     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1183
1184     // Register a counter with an invalid parent category name
1185     const Counter* noCounter = nullptr;
1186     BOOST_CHECK_THROW(noCounter =
1187                           counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1188                                                            0,
1189                                                            "",
1190                                                            0,
1191                                                            1,
1192                                                            123.45f,
1193                                                            "valid ",
1194                                                            "name"),
1195                       armnn::InvalidArgumentException);
1196     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1197     BOOST_CHECK(!noCounter);
1198
1199     // Register a counter with an invalid parent category name
1200     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1201                                                                    1,
1202                                                                    "invalid parent category",
1203                                                                    0,
1204                                                                    1,
1205                                                                    123.45f,
1206                                                                    "valid name",
1207                                                                    "valid description"),
1208                       armnn::InvalidArgumentException);
1209     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1210     BOOST_CHECK(!noCounter);
1211
1212     // Register a counter with an invalid class
1213     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1214                                                                    2,
1215                                                                    "valid_parent_category",
1216                                                                    2,
1217                                                                    1,
1218                                                                    123.45f,
1219                                                                    "valid "
1220                                                                    "name",
1221                                                                    "valid description"),
1222                       armnn::InvalidArgumentException);
1223     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1224     BOOST_CHECK(!noCounter);
1225
1226     // Register a counter with an invalid interpolation
1227     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1228                                                                    4,
1229                                                                    "valid_parent_category",
1230                                                                    0,
1231                                                                    3,
1232                                                                    123.45f,
1233                                                                    "valid "
1234                                                                    "name",
1235                                                                    "valid description"),
1236                       armnn::InvalidArgumentException);
1237     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1238     BOOST_CHECK(!noCounter);
1239
1240     // Register a counter with an invalid multiplier
1241     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1242                                                                    5,
1243                                                                    "valid_parent_category",
1244                                                                    0,
1245                                                                    1,
1246                                                                    .0f,
1247                                                                    "valid "
1248                                                                    "name",
1249                                                                    "valid description"),
1250                       armnn::InvalidArgumentException);
1251     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1252     BOOST_CHECK(!noCounter);
1253
1254     // Register a counter with an invalid name
1255     BOOST_CHECK_THROW(
1256         noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1257                                                      6,
1258                                                      "valid_parent_category",
1259                                                      0,
1260                                                      1,
1261                                                      123.45f,
1262                                                      "",
1263                                                      "valid description"),
1264         armnn::InvalidArgumentException);
1265     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1266     BOOST_CHECK(!noCounter);
1267
1268     // Register a counter with an invalid name
1269     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1270                                                                    7,
1271                                                                    "valid_parent_category",
1272                                                                    0,
1273                                                                    1,
1274                                                                    123.45f,
1275                                                                    "invalid nam€",
1276                                                                    "valid description"),
1277                       armnn::InvalidArgumentException);
1278     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1279     BOOST_CHECK(!noCounter);
1280
1281     // Register a counter with an invalid description
1282     BOOST_CHECK_THROW(noCounter =
1283                           counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1284                                                            8,
1285                                                            "valid_parent_category",
1286                                                            0,
1287                                                            1,
1288                                                            123.45f,
1289                                                            "valid name",
1290                                                            ""),
1291                       armnn::InvalidArgumentException);
1292     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1293     BOOST_CHECK(!noCounter);
1294
1295     // Register a counter with an invalid description
1296     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1297                                                                    9,
1298                                                                    "valid_parent_category",
1299                                                                    0,
1300                                                                    1,
1301                                                                    123.45f,
1302                                                                    "valid "
1303                                                                    "name",
1304                                                                    "inv@lid description"),
1305                       armnn::InvalidArgumentException);
1306     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1307     BOOST_CHECK(!noCounter);
1308
1309     // Register a counter with an invalid unit2
1310     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1311                                                                    10,
1312                                                                    "valid_parent_category",
1313                                                                    0,
1314                                                                    1,
1315                                                                    123.45f,
1316                                                                    "valid name",
1317                                                                    "valid description",
1318                                                                    std::string("Mb/s2")),
1319                       armnn::InvalidArgumentException);
1320     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1321     BOOST_CHECK(!noCounter);
1322
1323     // Register a counter with a non-existing parent category name
1324     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1325                                                                    11,
1326                                                                    "invalid_parent_category",
1327                                                                    0,
1328                                                                    1,
1329                                                                    123.45f,
1330                                                                    "valid name",
1331                                                                    "valid description"),
1332                       armnn::InvalidArgumentException);
1333     BOOST_CHECK(counterDirectory.GetCounterCount() == 0);
1334     BOOST_CHECK(!noCounter);
1335
1336     // Try getting an unregistered counter
1337     const Counter* unregisteredCounter = counterDirectory.GetCounter(9999);
1338     BOOST_CHECK(!unregisteredCounter);
1339
1340     // Register a category for testing
1341     const std::string categoryName = "some_category";
1342     const Category* category       = nullptr;
1343     BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName));
1344     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
1345     BOOST_CHECK(category);
1346     BOOST_CHECK(category->m_Name == categoryName);
1347     BOOST_CHECK(category->m_Counters.empty());
1348
1349     // Register a counter with a valid parent category name
1350     const Counter* counter = nullptr;
1351     BOOST_CHECK_NO_THROW(
1352         counter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1353                                                    12,
1354                                                    categoryName,
1355                                                    0,
1356                                                    1,
1357                                                    123.45f,
1358                                                    "valid name",
1359                                                    "valid description"));
1360     BOOST_CHECK(counterDirectory.GetCounterCount() == 1);
1361     BOOST_CHECK(counter);
1362     BOOST_CHECK(counter->m_MaxCounterUid == counter->m_Uid);
1363     BOOST_CHECK(counter->m_Class == 0);
1364     BOOST_CHECK(counter->m_Interpolation == 1);
1365     BOOST_CHECK(counter->m_Multiplier == 123.45f);
1366     BOOST_CHECK(counter->m_Name == "valid name");
1367     BOOST_CHECK(counter->m_Description == "valid description");
1368     BOOST_CHECK(counter->m_Units == "");
1369     BOOST_CHECK(counter->m_DeviceUid == 0);
1370     BOOST_CHECK(counter->m_CounterSetUid == 0);
1371     BOOST_CHECK(category->m_Counters.size() == 1);
1372     BOOST_CHECK(category->m_Counters.back() == counter->m_Uid);
1373
1374     // Register a counter with a name of a counter already registered for the given parent category name
1375     const Counter* counterSameName = nullptr;
1376     BOOST_CHECK_THROW(counterSameName =
1377                           counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1378                                                            13,
1379                                                            categoryName,
1380                                                            0,
1381                                                            0,
1382                                                            1.0f,
1383                                                            "valid name",
1384                                                            "valid description",
1385                                                            std::string("description")),
1386                       armnn::InvalidArgumentException);
1387     BOOST_CHECK(counterDirectory.GetCounterCount() == 1);
1388     BOOST_CHECK(!counterSameName);
1389
1390     // Register a counter with a valid parent category name and units
1391     const Counter* counterWUnits = nullptr;
1392     BOOST_CHECK_NO_THROW(counterWUnits = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1393                                                                              14,
1394                                                                              categoryName,
1395                                                                              0,
1396                                                                              1,
1397                                                                              123.45f,
1398                                                                              "valid name 2",
1399                                                                              "valid description",
1400                                                                              std::string("Mnnsq2")));    // Units
1401     BOOST_CHECK(counterDirectory.GetCounterCount() == 2);
1402     BOOST_CHECK(counterWUnits);
1403     BOOST_CHECK(counterWUnits->m_Uid > counter->m_Uid);
1404     BOOST_CHECK(counterWUnits->m_MaxCounterUid == counterWUnits->m_Uid);
1405     BOOST_CHECK(counterWUnits->m_Class == 0);
1406     BOOST_CHECK(counterWUnits->m_Interpolation == 1);
1407     BOOST_CHECK(counterWUnits->m_Multiplier == 123.45f);
1408     BOOST_CHECK(counterWUnits->m_Name == "valid name 2");
1409     BOOST_CHECK(counterWUnits->m_Description == "valid description");
1410     BOOST_CHECK(counterWUnits->m_Units == "Mnnsq2");
1411     BOOST_CHECK(counterWUnits->m_DeviceUid == 0);
1412     BOOST_CHECK(counterWUnits->m_CounterSetUid == 0);
1413     BOOST_CHECK(category->m_Counters.size() == 2);
1414     BOOST_CHECK(category->m_Counters.back() == counterWUnits->m_Uid);
1415
1416     // Register a counter with a valid parent category name and not associated with a device
1417     const Counter* counterWoDevice = nullptr;
1418     BOOST_CHECK_NO_THROW(counterWoDevice = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1419                                                                             26,
1420                                                                             categoryName,
1421                                                                             0,
1422                                                                             1,
1423                                                                             123.45f,
1424                                                                             "valid name 3",
1425                                                                             "valid description",
1426                                                                             armnn::EmptyOptional(),// Units
1427                                                                             armnn::EmptyOptional(),// Number of cores
1428                                                                             0));                   // Device UID
1429     BOOST_CHECK(counterDirectory.GetCounterCount() == 3);
1430     BOOST_CHECK(counterWoDevice);
1431     BOOST_CHECK(counterWoDevice->m_Uid > counter->m_Uid);
1432     BOOST_CHECK(counterWoDevice->m_MaxCounterUid == counterWoDevice->m_Uid);
1433     BOOST_CHECK(counterWoDevice->m_Class == 0);
1434     BOOST_CHECK(counterWoDevice->m_Interpolation == 1);
1435     BOOST_CHECK(counterWoDevice->m_Multiplier == 123.45f);
1436     BOOST_CHECK(counterWoDevice->m_Name == "valid name 3");
1437     BOOST_CHECK(counterWoDevice->m_Description == "valid description");
1438     BOOST_CHECK(counterWoDevice->m_Units == "");
1439     BOOST_CHECK(counterWoDevice->m_DeviceUid == 0);
1440     BOOST_CHECK(counterWoDevice->m_CounterSetUid == 0);
1441     BOOST_CHECK(category->m_Counters.size() == 3);
1442     BOOST_CHECK(category->m_Counters.back() == counterWoDevice->m_Uid);
1443
1444     // Register a counter with a valid parent category name and associated to an invalid device
1445     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1446                                                                    15,
1447                                                                    categoryName,
1448                                                                    0,
1449                                                                    1,
1450                                                                    123.45f,
1451                                                                    "valid name 4",
1452                                                                    "valid description",
1453                                                                    armnn::EmptyOptional(),    // Units
1454                                                                    armnn::EmptyOptional(),    // Number of cores
1455                                                                    100),                      // Device UID
1456                       armnn::InvalidArgumentException);
1457     BOOST_CHECK(counterDirectory.GetCounterCount() == 3);
1458     BOOST_CHECK(!noCounter);
1459
1460     // Register a device for testing
1461     const std::string deviceName = "some_device";
1462     const Device* device         = nullptr;
1463     BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName));
1464     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
1465     BOOST_CHECK(device);
1466     BOOST_CHECK(device->m_Name == deviceName);
1467     BOOST_CHECK(device->m_Uid >= 1);
1468     BOOST_CHECK(device->m_Cores == 0);
1469
1470     // Register a counter with a valid parent category name and associated to a device
1471     const Counter* counterWDevice = nullptr;
1472     BOOST_CHECK_NO_THROW(counterWDevice = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1473                                                                            16,
1474                                                                            categoryName,
1475                                                                            0,
1476                                                                            1,
1477                                                                            123.45f,
1478                                                                            "valid name 5",
1479                                                                            std::string("valid description"),
1480                                                                            armnn::EmptyOptional(), // Units
1481                                                                            armnn::EmptyOptional(), // Number of cores
1482                                                                            device->m_Uid));        // Device UID
1483     BOOST_CHECK(counterDirectory.GetCounterCount() == 4);
1484     BOOST_CHECK(counterWDevice);
1485     BOOST_CHECK(counterWDevice->m_Uid > counter->m_Uid);
1486     BOOST_CHECK(counterWDevice->m_MaxCounterUid == counterWDevice->m_Uid);
1487     BOOST_CHECK(counterWDevice->m_Class == 0);
1488     BOOST_CHECK(counterWDevice->m_Interpolation == 1);
1489     BOOST_CHECK(counterWDevice->m_Multiplier == 123.45f);
1490     BOOST_CHECK(counterWDevice->m_Name == "valid name 5");
1491     BOOST_CHECK(counterWDevice->m_Description == "valid description");
1492     BOOST_CHECK(counterWDevice->m_Units == "");
1493     BOOST_CHECK(counterWDevice->m_DeviceUid == device->m_Uid);
1494     BOOST_CHECK(counterWDevice->m_CounterSetUid == 0);
1495     BOOST_CHECK(category->m_Counters.size() == 4);
1496     BOOST_CHECK(category->m_Counters.back() == counterWDevice->m_Uid);
1497
1498     // Register a counter with a valid parent category name and not associated with a counter set
1499     const Counter* counterWoCounterSet = nullptr;
1500     BOOST_CHECK_NO_THROW(counterWoCounterSet = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1501                                                                                 17,
1502                                                                                 categoryName,
1503                                                                                 0,
1504                                                                                 1,
1505                                                                                 123.45f,
1506                                                                                 "valid name 6",
1507                                                                                 "valid description",
1508                                                                                 armnn::EmptyOptional(),// Units
1509                                                                                 armnn::EmptyOptional(),// No of cores
1510                                                                                 armnn::EmptyOptional(),// Device UID
1511                                                                                 0));               // CounterSet UID
1512     BOOST_CHECK(counterDirectory.GetCounterCount() == 5);
1513     BOOST_CHECK(counterWoCounterSet);
1514     BOOST_CHECK(counterWoCounterSet->m_Uid > counter->m_Uid);
1515     BOOST_CHECK(counterWoCounterSet->m_MaxCounterUid == counterWoCounterSet->m_Uid);
1516     BOOST_CHECK(counterWoCounterSet->m_Class == 0);
1517     BOOST_CHECK(counterWoCounterSet->m_Interpolation == 1);
1518     BOOST_CHECK(counterWoCounterSet->m_Multiplier == 123.45f);
1519     BOOST_CHECK(counterWoCounterSet->m_Name == "valid name 6");
1520     BOOST_CHECK(counterWoCounterSet->m_Description == "valid description");
1521     BOOST_CHECK(counterWoCounterSet->m_Units == "");
1522     BOOST_CHECK(counterWoCounterSet->m_DeviceUid == 0);
1523     BOOST_CHECK(counterWoCounterSet->m_CounterSetUid == 0);
1524     BOOST_CHECK(category->m_Counters.size() == 5);
1525     BOOST_CHECK(category->m_Counters.back() == counterWoCounterSet->m_Uid);
1526
1527     // Register a counter with a valid parent category name and associated to an invalid counter set
1528     BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1529                                                                    18,
1530                                                                    categoryName,
1531                                                                    0,
1532                                                                    1,
1533                                                                    123.45f,
1534                                                                    "valid ",
1535                                                                    "name 7",
1536                                                                    std::string("valid description"),
1537                                                                    armnn::EmptyOptional(),    // Units
1538                                                                    armnn::EmptyOptional(),    // Number of cores
1539                                                                    100),            // Counter set UID
1540                       armnn::InvalidArgumentException);
1541     BOOST_CHECK(counterDirectory.GetCounterCount() == 5);
1542     BOOST_CHECK(!noCounter);
1543
1544     // Register a counter with a valid parent category name and with a given number of cores
1545     const Counter* counterWNumberOfCores = nullptr;
1546     uint16_t numberOfCores               = 15;
1547     BOOST_CHECK_NO_THROW(counterWNumberOfCores = counterDirectory.RegisterCounter(
1548                              armnn::profiling::BACKEND_ID, 50,
1549                              categoryName, 0, 1, 123.45f, "valid name 8", "valid description",
1550                              armnn::EmptyOptional(),      // Units
1551                              numberOfCores,               // Number of cores
1552                              armnn::EmptyOptional(),      // Device UID
1553                              armnn::EmptyOptional()));    // Counter set UID
1554     BOOST_CHECK(counterDirectory.GetCounterCount() == 20);
1555     BOOST_CHECK(counterWNumberOfCores);
1556     BOOST_CHECK(counterWNumberOfCores->m_Uid > counter->m_Uid);
1557     BOOST_CHECK(counterWNumberOfCores->m_MaxCounterUid == counterWNumberOfCores->m_Uid + numberOfCores - 1);
1558     BOOST_CHECK(counterWNumberOfCores->m_Class == 0);
1559     BOOST_CHECK(counterWNumberOfCores->m_Interpolation == 1);
1560     BOOST_CHECK(counterWNumberOfCores->m_Multiplier == 123.45f);
1561     BOOST_CHECK(counterWNumberOfCores->m_Name == "valid name 8");
1562     BOOST_CHECK(counterWNumberOfCores->m_Description == "valid description");
1563     BOOST_CHECK(counterWNumberOfCores->m_Units == "");
1564     BOOST_CHECK(counterWNumberOfCores->m_DeviceUid == 0);
1565     BOOST_CHECK(counterWNumberOfCores->m_CounterSetUid == 0);
1566     BOOST_CHECK(category->m_Counters.size() == 20);
1567     for (size_t i = 0; i < numberOfCores; i++)
1568     {
1569         BOOST_CHECK(category->m_Counters[category->m_Counters.size() - numberOfCores + i] ==
1570                     counterWNumberOfCores->m_Uid + i);
1571     }
1572
1573     // Register a multi-core device for testing
1574     const std::string multiCoreDeviceName = "some_multi_core_device";
1575     const Device* multiCoreDevice         = nullptr;
1576     BOOST_CHECK_NO_THROW(multiCoreDevice = counterDirectory.RegisterDevice(multiCoreDeviceName, 4));
1577     BOOST_CHECK(counterDirectory.GetDeviceCount() == 2);
1578     BOOST_CHECK(multiCoreDevice);
1579     BOOST_CHECK(multiCoreDevice->m_Name == multiCoreDeviceName);
1580     BOOST_CHECK(multiCoreDevice->m_Uid >= 1);
1581     BOOST_CHECK(multiCoreDevice->m_Cores == 4);
1582
1583     // Register a counter with a valid parent category name and associated to the multi-core device
1584     const Counter* counterWMultiCoreDevice = nullptr;
1585     BOOST_CHECK_NO_THROW(counterWMultiCoreDevice = counterDirectory.RegisterCounter(
1586                              armnn::profiling::BACKEND_ID, 19, categoryName, 0, 1,
1587                              123.45f, "valid name 9", "valid description",
1588                              armnn::EmptyOptional(),      // Units
1589                              armnn::EmptyOptional(),      // Number of cores
1590                              multiCoreDevice->m_Uid,      // Device UID
1591                              armnn::EmptyOptional()));    // Counter set UID
1592     BOOST_CHECK(counterDirectory.GetCounterCount() == 24);
1593     BOOST_CHECK(counterWMultiCoreDevice);
1594     BOOST_CHECK(counterWMultiCoreDevice->m_Uid > counter->m_Uid);
1595     BOOST_CHECK(counterWMultiCoreDevice->m_MaxCounterUid ==
1596                 counterWMultiCoreDevice->m_Uid + multiCoreDevice->m_Cores - 1);
1597     BOOST_CHECK(counterWMultiCoreDevice->m_Class == 0);
1598     BOOST_CHECK(counterWMultiCoreDevice->m_Interpolation == 1);
1599     BOOST_CHECK(counterWMultiCoreDevice->m_Multiplier == 123.45f);
1600     BOOST_CHECK(counterWMultiCoreDevice->m_Name == "valid name 9");
1601     BOOST_CHECK(counterWMultiCoreDevice->m_Description == "valid description");
1602     BOOST_CHECK(counterWMultiCoreDevice->m_Units == "");
1603     BOOST_CHECK(counterWMultiCoreDevice->m_DeviceUid == multiCoreDevice->m_Uid);
1604     BOOST_CHECK(counterWMultiCoreDevice->m_CounterSetUid == 0);
1605     BOOST_CHECK(category->m_Counters.size() == 24);
1606     for (size_t i = 0; i < 4; i++)
1607     {
1608         BOOST_CHECK(category->m_Counters[category->m_Counters.size() - 4 + i] == counterWMultiCoreDevice->m_Uid + i);
1609     }
1610
1611     // Register a multi-core device associate to a parent category for testing
1612     const std::string multiCoreDeviceNameWParentCategory = "some_multi_core_device_with_parent_category";
1613     const Device* multiCoreDeviceWParentCategory         = nullptr;
1614     BOOST_CHECK_NO_THROW(multiCoreDeviceWParentCategory =
1615                              counterDirectory.RegisterDevice(multiCoreDeviceNameWParentCategory, 2, categoryName));
1616     BOOST_CHECK(counterDirectory.GetDeviceCount() == 3);
1617     BOOST_CHECK(multiCoreDeviceWParentCategory);
1618     BOOST_CHECK(multiCoreDeviceWParentCategory->m_Name == multiCoreDeviceNameWParentCategory);
1619     BOOST_CHECK(multiCoreDeviceWParentCategory->m_Uid >= 1);
1620     BOOST_CHECK(multiCoreDeviceWParentCategory->m_Cores == 2);
1621
1622     // Register a counter with a valid parent category name and getting the number of cores of the multi-core device
1623     // associated to that category
1624     const Counter* counterWMultiCoreDeviceWParentCategory = nullptr;
1625     uint16_t numberOfCourse = multiCoreDeviceWParentCategory->m_Cores;
1626     BOOST_CHECK_NO_THROW(counterWMultiCoreDeviceWParentCategory =
1627                                                 counterDirectory.RegisterCounter(
1628                                                     armnn::profiling::BACKEND_ID,
1629                                                     100,
1630                                                     categoryName,
1631                                                     0,
1632                                                     1,
1633                                                     123.45f,
1634                                                     "valid name 10",
1635                                                     "valid description",
1636                                                     armnn::EmptyOptional(),  // Units
1637                                                     numberOfCourse,          // Number of cores
1638                                                     armnn::EmptyOptional(),  // Device UID
1639                                                     armnn::EmptyOptional()));// Counter set UID
1640     BOOST_CHECK(counterDirectory.GetCounterCount() == 26);
1641     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory);
1642     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_Uid > counter->m_Uid);
1643     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_MaxCounterUid ==
1644                 counterWMultiCoreDeviceWParentCategory->m_Uid + multiCoreDeviceWParentCategory->m_Cores - 1);
1645     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_Class == 0);
1646     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_Interpolation == 1);
1647     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_Multiplier == 123.45f);
1648     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_Name == "valid name 10");
1649     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_Description == "valid description");
1650     BOOST_CHECK(counterWMultiCoreDeviceWParentCategory->m_Units == "");
1651     BOOST_CHECK(category->m_Counters.size() == 26);
1652     for (size_t i = 0; i < 2; i++)
1653     {
1654         BOOST_CHECK(category->m_Counters[category->m_Counters.size() - 2 + i] ==
1655                     counterWMultiCoreDeviceWParentCategory->m_Uid + i);
1656     }
1657
1658     // Register a counter set for testing
1659     const std::string counterSetName = "some_counter_set";
1660     const CounterSet* counterSet     = nullptr;
1661     BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1662     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1663     BOOST_CHECK(counterSet);
1664     BOOST_CHECK(counterSet->m_Name == counterSetName);
1665     BOOST_CHECK(counterSet->m_Uid >= 1);
1666     BOOST_CHECK(counterSet->m_Count == 0);
1667
1668     // Register a counter with a valid parent category name and associated to a counter set
1669     const Counter* counterWCounterSet = nullptr;
1670     BOOST_CHECK_NO_THROW(counterWCounterSet = counterDirectory.RegisterCounter(
1671                              armnn::profiling::BACKEND_ID, 300,
1672                              categoryName, 0, 1, 123.45f, "valid name 11", "valid description",
1673                              armnn::EmptyOptional(),    // Units
1674                              0,                         // Number of cores
1675                              armnn::EmptyOptional(),    // Device UID
1676                              counterSet->m_Uid));       // Counter set UID
1677     BOOST_CHECK(counterDirectory.GetCounterCount() == 27);
1678     BOOST_CHECK(counterWCounterSet);
1679     BOOST_CHECK(counterWCounterSet->m_Uid > counter->m_Uid);
1680     BOOST_CHECK(counterWCounterSet->m_MaxCounterUid == counterWCounterSet->m_Uid);
1681     BOOST_CHECK(counterWCounterSet->m_Class == 0);
1682     BOOST_CHECK(counterWCounterSet->m_Interpolation == 1);
1683     BOOST_CHECK(counterWCounterSet->m_Multiplier == 123.45f);
1684     BOOST_CHECK(counterWCounterSet->m_Name == "valid name 11");
1685     BOOST_CHECK(counterWCounterSet->m_Description == "valid description");
1686     BOOST_CHECK(counterWCounterSet->m_Units == "");
1687     BOOST_CHECK(counterWCounterSet->m_DeviceUid == 0);
1688     BOOST_CHECK(counterWCounterSet->m_CounterSetUid == counterSet->m_Uid);
1689     BOOST_CHECK(category->m_Counters.size() == 27);
1690     BOOST_CHECK(category->m_Counters.back() == counterWCounterSet->m_Uid);
1691
1692     // Register a counter with a valid parent category name and associated to a device and a counter set
1693     const Counter* counterWDeviceWCounterSet = nullptr;
1694     BOOST_CHECK_NO_THROW(counterWDeviceWCounterSet = counterDirectory.RegisterCounter(
1695                              armnn::profiling::BACKEND_ID, 23,
1696                              categoryName, 0, 1, 123.45f, "valid name 12", "valid description",
1697                              armnn::EmptyOptional(),    // Units
1698                              1,                         // Number of cores
1699                              device->m_Uid,             // Device UID
1700                              counterSet->m_Uid));       // Counter set UID
1701     BOOST_CHECK(counterDirectory.GetCounterCount() == 28);
1702     BOOST_CHECK(counterWDeviceWCounterSet);
1703     BOOST_CHECK(counterWDeviceWCounterSet->m_Uid > counter->m_Uid);
1704     BOOST_CHECK(counterWDeviceWCounterSet->m_MaxCounterUid == counterWDeviceWCounterSet->m_Uid);
1705     BOOST_CHECK(counterWDeviceWCounterSet->m_Class == 0);
1706     BOOST_CHECK(counterWDeviceWCounterSet->m_Interpolation == 1);
1707     BOOST_CHECK(counterWDeviceWCounterSet->m_Multiplier == 123.45f);
1708     BOOST_CHECK(counterWDeviceWCounterSet->m_Name == "valid name 12");
1709     BOOST_CHECK(counterWDeviceWCounterSet->m_Description == "valid description");
1710     BOOST_CHECK(counterWDeviceWCounterSet->m_Units == "");
1711     BOOST_CHECK(counterWDeviceWCounterSet->m_DeviceUid == device->m_Uid);
1712     BOOST_CHECK(counterWDeviceWCounterSet->m_CounterSetUid == counterSet->m_Uid);
1713     BOOST_CHECK(category->m_Counters.size() == 28);
1714     BOOST_CHECK(category->m_Counters.back() == counterWDeviceWCounterSet->m_Uid);
1715
1716     // Register another category for testing
1717     const std::string anotherCategoryName = "some_other_category";
1718     const Category* anotherCategory       = nullptr;
1719     BOOST_CHECK_NO_THROW(anotherCategory = counterDirectory.RegisterCategory(anotherCategoryName));
1720     BOOST_CHECK(counterDirectory.GetCategoryCount() == 2);
1721     BOOST_CHECK(anotherCategory);
1722     BOOST_CHECK(anotherCategory != category);
1723     BOOST_CHECK(anotherCategory->m_Name == anotherCategoryName);
1724     BOOST_CHECK(anotherCategory->m_Counters.empty());
1725
1726     // Register a counter to the other category
1727     const Counter* anotherCounter = nullptr;
1728     BOOST_CHECK_NO_THROW(anotherCounter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID, 24,
1729                                                                            anotherCategoryName, 1, 0, .00043f,
1730                                                                            "valid name", "valid description",
1731                                                                            armnn::EmptyOptional(), // Units
1732                                                                            armnn::EmptyOptional(), // Number of cores
1733                                                                            device->m_Uid,          // Device UID
1734                                                                            counterSet->m_Uid));    // Counter set UID
1735     BOOST_CHECK(counterDirectory.GetCounterCount() == 29);
1736     BOOST_CHECK(anotherCounter);
1737     BOOST_CHECK(anotherCounter->m_MaxCounterUid == anotherCounter->m_Uid);
1738     BOOST_CHECK(anotherCounter->m_Class == 1);
1739     BOOST_CHECK(anotherCounter->m_Interpolation == 0);
1740     BOOST_CHECK(anotherCounter->m_Multiplier == .00043f);
1741     BOOST_CHECK(anotherCounter->m_Name == "valid name");
1742     BOOST_CHECK(anotherCounter->m_Description == "valid description");
1743     BOOST_CHECK(anotherCounter->m_Units == "");
1744     BOOST_CHECK(anotherCounter->m_DeviceUid == device->m_Uid);
1745     BOOST_CHECK(anotherCounter->m_CounterSetUid == counterSet->m_Uid);
1746     BOOST_CHECK(anotherCategory->m_Counters.size() == 1);
1747     BOOST_CHECK(anotherCategory->m_Counters.back() == anotherCounter->m_Uid);
1748 }
1749
1750 BOOST_AUTO_TEST_CASE(CounterSelectionCommandHandlerParseData)
1751 {
1752     ProfilingStateMachine profilingStateMachine;
1753
1754     class TestCaptureThread : public IPeriodicCounterCapture
1755     {
1756         void Start() override
1757         {}
1758         void Stop() override
1759         {}
1760     };
1761
1762     class TestReadCounterValues : public IReadCounterValues
1763     {
1764         bool IsCounterRegistered(uint16_t counterUid) const override
1765         {
1766             armnn::IgnoreUnused(counterUid);
1767             return true;
1768         }
1769         uint16_t GetCounterCount() const override
1770         {
1771             return 0;
1772         }
1773         uint32_t GetAbsoluteCounterValue(uint16_t counterUid) const override
1774         {
1775             armnn::IgnoreUnused(counterUid);
1776             return 0;
1777         }
1778         uint32_t GetDeltaCounterValue(uint16_t counterUid) override
1779         {
1780             armnn::IgnoreUnused(counterUid);
1781             return 0;
1782         }
1783     };
1784     const uint32_t familyId = 0;
1785     const uint32_t packetId = 0x40000;
1786
1787     uint32_t version = 1;
1788     const std::unordered_map<armnn::BackendId,
1789             std::shared_ptr<armnn::profiling::IBackendProfilingContext>> backendProfilingContext;
1790     CounterIdMap counterIdMap;
1791     Holder holder;
1792     TestCaptureThread captureThread;
1793     TestReadCounterValues readCounterValues;
1794     MockBufferManager mockBuffer(512);
1795     SendCounterPacket sendCounterPacket(mockBuffer);
1796     SendThread sendThread(profilingStateMachine, mockBuffer, sendCounterPacket);
1797
1798     uint32_t sizeOfUint32 = armnn::numeric_cast<uint32_t>(sizeof(uint32_t));
1799     uint32_t sizeOfUint16 = armnn::numeric_cast<uint32_t>(sizeof(uint16_t));
1800
1801     // Data with period and counters
1802     uint32_t period1     = armnn::LOWEST_CAPTURE_PERIOD;
1803     uint32_t dataLength1 = 8;
1804     uint32_t offset      = 0;
1805
1806     std::unique_ptr<unsigned char[]> uniqueData1 = std::make_unique<unsigned char[]>(dataLength1);
1807     unsigned char* data1                         = reinterpret_cast<unsigned char*>(uniqueData1.get());
1808
1809     WriteUint32(data1, offset, period1);
1810     offset += sizeOfUint32;
1811     WriteUint16(data1, offset, 4000);
1812     offset += sizeOfUint16;
1813     WriteUint16(data1, offset, 5000);
1814
1815     arm::pipe::Packet packetA(packetId, dataLength1, uniqueData1);
1816
1817     PeriodicCounterSelectionCommandHandler commandHandler(familyId, packetId, version, backendProfilingContext,
1818                                                           counterIdMap, holder, 10000u, captureThread,
1819                                                           readCounterValues, sendCounterPacket, profilingStateMachine);
1820
1821     profilingStateMachine.TransitionToState(ProfilingState::Uninitialised);
1822     BOOST_CHECK_THROW(commandHandler(packetA), armnn::RuntimeException);
1823     profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
1824     BOOST_CHECK_THROW(commandHandler(packetA), armnn::RuntimeException);
1825     profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
1826     BOOST_CHECK_THROW(commandHandler(packetA), armnn::RuntimeException);
1827     profilingStateMachine.TransitionToState(ProfilingState::Active);
1828     BOOST_CHECK_NO_THROW(commandHandler(packetA));
1829
1830     const std::vector<uint16_t> counterIdsA = holder.GetCaptureData().GetCounterIds();
1831
1832     BOOST_TEST(holder.GetCaptureData().GetCapturePeriod() == period1);
1833     BOOST_TEST(counterIdsA.size() == 2);
1834     BOOST_TEST(counterIdsA[0] == 4000);
1835     BOOST_TEST(counterIdsA[1] == 5000);
1836
1837     auto readBuffer = mockBuffer.GetReadableBuffer();
1838
1839     offset = 0;
1840
1841     uint32_t headerWord0 = ReadUint32(readBuffer, offset);
1842     offset += sizeOfUint32;
1843     uint32_t headerWord1 = ReadUint32(readBuffer, offset);
1844     offset += sizeOfUint32;
1845     uint32_t period = ReadUint32(readBuffer, offset);
1846
1847     BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0);             // packet family
1848     BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 4);            // packet id
1849     BOOST_TEST(headerWord1 == 8);                              // data length
1850     BOOST_TEST(period ==  armnn::LOWEST_CAPTURE_PERIOD);       // capture period
1851
1852     uint16_t counterId = 0;
1853     offset += sizeOfUint32;
1854     counterId = ReadUint16(readBuffer, offset);
1855     BOOST_TEST(counterId == 4000);
1856     offset += sizeOfUint16;
1857     counterId = ReadUint16(readBuffer, offset);
1858     BOOST_TEST(counterId == 5000);
1859
1860     mockBuffer.MarkRead(readBuffer);
1861
1862     // Data with period only
1863     uint32_t period2     = 9000; // We'll specify a value below LOWEST_CAPTURE_PERIOD. It should be pulled upwards.
1864     uint32_t dataLength2 = 4;
1865
1866     std::unique_ptr<unsigned char[]> uniqueData2 = std::make_unique<unsigned char[]>(dataLength2);
1867
1868     WriteUint32(reinterpret_cast<unsigned char*>(uniqueData2.get()), 0, period2);
1869
1870     arm::pipe::Packet packetB(packetId, dataLength2, uniqueData2);
1871
1872     commandHandler(packetB);
1873
1874     const std::vector<uint16_t> counterIdsB = holder.GetCaptureData().GetCounterIds();
1875
1876     // Value should have been pulled up from 9000 to LOWEST_CAPTURE_PERIOD.
1877     BOOST_TEST(holder.GetCaptureData().GetCapturePeriod() ==  armnn::LOWEST_CAPTURE_PERIOD);
1878     BOOST_TEST(counterIdsB.size() == 0);
1879
1880     readBuffer = mockBuffer.GetReadableBuffer();
1881
1882     offset = 0;
1883
1884     headerWord0 = ReadUint32(readBuffer, offset);
1885     offset += sizeOfUint32;
1886     headerWord1 = ReadUint32(readBuffer, offset);
1887     offset += sizeOfUint32;
1888     period = ReadUint32(readBuffer, offset);
1889
1890     BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0);         // packet family
1891     BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 4);        // packet id
1892     BOOST_TEST(headerWord1 == 4);                          // data length
1893     BOOST_TEST(period == armnn::LOWEST_CAPTURE_PERIOD);    // capture period
1894 }
1895
1896 BOOST_AUTO_TEST_CASE(CheckTimelineActivationAndDeactivation)
1897 {
1898     class TestReportStructure : public IReportStructure
1899     {
1900         public:
1901         virtual void ReportStructure() override
1902         {
1903             m_ReportStructureCalled = true;
1904         }
1905
1906         bool m_ReportStructureCalled = false;
1907     };
1908
1909     class TestNotifyBackends : public INotifyBackends
1910     {
1911         public:
1912         TestNotifyBackends() : m_timelineReporting(false) {}
1913         virtual void NotifyBackendsForTimelineReporting() override
1914         {
1915             m_TestNotifyBackendsCalled = m_timelineReporting.load();
1916         }
1917
1918         bool m_TestNotifyBackendsCalled = false;
1919         std::atomic<bool> m_timelineReporting;
1920     };
1921
1922     arm::pipe::PacketVersionResolver packetVersionResolver;
1923
1924     BufferManager bufferManager(512);
1925     SendTimelinePacket sendTimelinePacket(bufferManager);
1926     ProfilingStateMachine stateMachine;
1927     TestReportStructure testReportStructure;
1928     TestNotifyBackends testNotifyBackends;
1929
1930     profiling::ActivateTimelineReportingCommandHandler activateTimelineReportingCommandHandler(0,
1931                                                            6,
1932                                                            packetVersionResolver.ResolvePacketVersion(0, 6)
1933                                                            .GetEncodedValue(),
1934                                                            sendTimelinePacket,
1935                                                            stateMachine,
1936                                                            testReportStructure,
1937                                                            testNotifyBackends.m_timelineReporting,
1938                                                            testNotifyBackends);
1939
1940     // Write an "ActivateTimelineReporting" packet into the mock profiling connection, to simulate an input from an
1941     // external profiling service
1942     const uint32_t packetFamily1 = 0;
1943     const uint32_t packetId1     = 6;
1944     uint32_t packetHeader1 = ConstructHeader(packetFamily1, packetId1);
1945
1946     // Create the ActivateTimelineReportingPacket
1947     arm::pipe::Packet ActivateTimelineReportingPacket(packetHeader1); // Length == 0
1948
1949     BOOST_CHECK_THROW(
1950             activateTimelineReportingCommandHandler.operator()(ActivateTimelineReportingPacket), armnn::Exception);
1951
1952     stateMachine.TransitionToState(ProfilingState::NotConnected);
1953     BOOST_CHECK_THROW(
1954             activateTimelineReportingCommandHandler.operator()(ActivateTimelineReportingPacket), armnn::Exception);
1955
1956     stateMachine.TransitionToState(ProfilingState::WaitingForAck);
1957     BOOST_CHECK_THROW(
1958             activateTimelineReportingCommandHandler.operator()(ActivateTimelineReportingPacket), armnn::Exception);
1959
1960     stateMachine.TransitionToState(ProfilingState::Active);
1961     activateTimelineReportingCommandHandler.operator()(ActivateTimelineReportingPacket);
1962
1963     BOOST_CHECK(testReportStructure.m_ReportStructureCalled);
1964     BOOST_CHECK(testNotifyBackends.m_TestNotifyBackendsCalled);
1965     BOOST_CHECK(testNotifyBackends.m_timelineReporting.load());
1966
1967     DeactivateTimelineReportingCommandHandler deactivateTimelineReportingCommandHandler(0,
1968                                                   7,
1969                                                   packetVersionResolver.ResolvePacketVersion(0, 7).GetEncodedValue(),
1970                                                   testNotifyBackends.m_timelineReporting,
1971                                                   stateMachine,
1972                                                   testNotifyBackends);
1973
1974     const uint32_t packetFamily2 = 0;
1975     const uint32_t packetId2     = 7;
1976     uint32_t packetHeader2 = ConstructHeader(packetFamily2, packetId2);
1977
1978     // Create the DeactivateTimelineReportingPacket
1979     arm::pipe::Packet deactivateTimelineReportingPacket(packetHeader2); // Length == 0
1980
1981     stateMachine.Reset();
1982     BOOST_CHECK_THROW(
1983             deactivateTimelineReportingCommandHandler.operator()(deactivateTimelineReportingPacket), armnn::Exception);
1984
1985     stateMachine.TransitionToState(ProfilingState::NotConnected);
1986     BOOST_CHECK_THROW(
1987             deactivateTimelineReportingCommandHandler.operator()(deactivateTimelineReportingPacket), armnn::Exception);
1988
1989     stateMachine.TransitionToState(ProfilingState::WaitingForAck);
1990     BOOST_CHECK_THROW(
1991             deactivateTimelineReportingCommandHandler.operator()(deactivateTimelineReportingPacket), armnn::Exception);
1992
1993     stateMachine.TransitionToState(ProfilingState::Active);
1994     deactivateTimelineReportingCommandHandler.operator()(deactivateTimelineReportingPacket);
1995
1996     BOOST_CHECK(!testNotifyBackends.m_TestNotifyBackendsCalled);
1997     BOOST_CHECK(!testNotifyBackends.m_timelineReporting.load());
1998 }
1999
2000 BOOST_AUTO_TEST_CASE(CheckProfilingServiceNotActive)
2001 {
2002     using namespace armnn;
2003     using namespace armnn::profiling;
2004
2005     // Create runtime in which the test will run
2006     armnn::IRuntime::CreationOptions options;
2007     options.m_ProfilingOptions.m_EnableProfiling = true;
2008
2009     armnn::Runtime runtime(options);
2010     profiling::ProfilingServiceRuntimeHelper profilingServiceHelper(GetProfilingService(&runtime));
2011     profilingServiceHelper.ForceTransitionToState(ProfilingState::NotConnected);
2012     profilingServiceHelper.ForceTransitionToState(ProfilingState::WaitingForAck);
2013     profilingServiceHelper.ForceTransitionToState(ProfilingState::Active);
2014
2015     profiling::BufferManager& bufferManager = profilingServiceHelper.GetProfilingBufferManager();
2016     auto readableBuffer = bufferManager.GetReadableBuffer();
2017
2018     // Profiling is enabled, the post-optimisation structure should be created
2019     BOOST_CHECK(readableBuffer == nullptr);
2020 }
2021
2022 BOOST_AUTO_TEST_CASE(CheckConnectionAcknowledged)
2023 {
2024     const uint32_t packetFamilyId     = 0;
2025     const uint32_t connectionPacketId = 0x10000;
2026     const uint32_t version            = 1;
2027
2028     uint32_t sizeOfUint32 = armnn::numeric_cast<uint32_t>(sizeof(uint32_t));
2029     uint32_t sizeOfUint16 = armnn::numeric_cast<uint32_t>(sizeof(uint16_t));
2030
2031     // Data with period and counters
2032     uint32_t period1     = 10;
2033     uint32_t dataLength1 = 8;
2034     uint32_t offset      = 0;
2035
2036     std::unique_ptr<unsigned char[]> uniqueData1 = std::make_unique<unsigned char[]>(dataLength1);
2037     unsigned char* data1                         = reinterpret_cast<unsigned char*>(uniqueData1.get());
2038
2039     WriteUint32(data1, offset, period1);
2040     offset += sizeOfUint32;
2041     WriteUint16(data1, offset, 4000);
2042     offset += sizeOfUint16;
2043     WriteUint16(data1, offset, 5000);
2044
2045     arm::pipe::Packet packetA(connectionPacketId, dataLength1, uniqueData1);
2046
2047     ProfilingStateMachine profilingState(ProfilingState::Uninitialised);
2048     BOOST_CHECK(profilingState.GetCurrentState() == ProfilingState::Uninitialised);
2049     CounterDirectory counterDirectory;
2050     MockBufferManager mockBuffer(1024);
2051     SendCounterPacket sendCounterPacket(mockBuffer);
2052     SendThread sendThread(profilingState, mockBuffer, sendCounterPacket);
2053     SendTimelinePacket sendTimelinePacket(mockBuffer);
2054     MockProfilingServiceStatus mockProfilingServiceStatus;
2055
2056     ConnectionAcknowledgedCommandHandler commandHandler(packetFamilyId,
2057                                                         connectionPacketId,
2058                                                         version,
2059                                                         counterDirectory,
2060                                                         sendCounterPacket,
2061                                                         sendTimelinePacket,
2062                                                         profilingState,
2063                                                         mockProfilingServiceStatus);
2064
2065     // command handler received packet on ProfilingState::Uninitialised
2066     BOOST_CHECK_THROW(commandHandler(packetA), armnn::Exception);
2067
2068     profilingState.TransitionToState(ProfilingState::NotConnected);
2069     BOOST_CHECK(profilingState.GetCurrentState() == ProfilingState::NotConnected);
2070     // command handler received packet on ProfilingState::NotConnected
2071     BOOST_CHECK_THROW(commandHandler(packetA), armnn::Exception);
2072
2073     profilingState.TransitionToState(ProfilingState::WaitingForAck);
2074     BOOST_CHECK(profilingState.GetCurrentState() == ProfilingState::WaitingForAck);
2075     // command handler received packet on ProfilingState::WaitingForAck
2076     BOOST_CHECK_NO_THROW(commandHandler(packetA));
2077     BOOST_CHECK(profilingState.GetCurrentState() == ProfilingState::Active);
2078
2079     // command handler received packet on ProfilingState::Active
2080     BOOST_CHECK_NO_THROW(commandHandler(packetA));
2081     BOOST_CHECK(profilingState.GetCurrentState() == ProfilingState::Active);
2082
2083     // command handler received different packet
2084     const uint32_t differentPacketId = 0x40000;
2085     arm::pipe::Packet packetB(differentPacketId, dataLength1, uniqueData1);
2086     profilingState.TransitionToState(ProfilingState::NotConnected);
2087     profilingState.TransitionToState(ProfilingState::WaitingForAck);
2088     ConnectionAcknowledgedCommandHandler differentCommandHandler(packetFamilyId,
2089                                                                  differentPacketId,
2090                                                                  version,
2091                                                                  counterDirectory,
2092                                                                  sendCounterPacket,
2093                                                                  sendTimelinePacket,
2094                                                                  profilingState,
2095                                                                  mockProfilingServiceStatus);
2096     BOOST_CHECK_THROW(differentCommandHandler(packetB), armnn::Exception);
2097 }
2098
2099 BOOST_AUTO_TEST_CASE(CheckSocketConnectionException)
2100 {
2101     // Check that creating a SocketProfilingConnection armnnProfiling in an exception as the Gator UDS doesn't exist.
2102     BOOST_CHECK_THROW(new SocketProfilingConnection(), arm::pipe::SocketConnectionException);
2103 }
2104
2105 BOOST_AUTO_TEST_CASE(CheckSocketConnectionException2)
2106 {
2107     try
2108     {
2109         new SocketProfilingConnection();
2110     }
2111     catch (const arm::pipe::SocketConnectionException& ex)
2112     {
2113         BOOST_CHECK(ex.GetSocketFd() == 0);
2114         BOOST_CHECK(ex.GetErrorNo() == 111);
2115         BOOST_CHECK(ex.what()
2116                     == std::string("SocketProfilingConnection: Cannot connect to stream socket: Connection refused"));
2117     }
2118 }
2119
2120 BOOST_AUTO_TEST_CASE(SwTraceIsValidCharTest)
2121 {
2122     // Only ASCII 7-bit encoding supported
2123     for (unsigned char c = 0; c < 128; c++)
2124     {
2125         BOOST_CHECK(arm::pipe::SwTraceCharPolicy::IsValidChar(c));
2126     }
2127
2128     // Not ASCII
2129     for (unsigned char c = 255; c >= 128; c++)
2130     {
2131         BOOST_CHECK(!arm::pipe::SwTraceCharPolicy::IsValidChar(c));
2132     }
2133 }
2134
2135 BOOST_AUTO_TEST_CASE(SwTraceIsValidNameCharTest)
2136 {
2137     // Only alpha-numeric and underscore ASCII 7-bit encoding supported
2138     const unsigned char validChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
2139     for (unsigned char i = 0; i < sizeof(validChars) / sizeof(validChars[0]) - 1; i++)
2140     {
2141         BOOST_CHECK(arm::pipe::SwTraceNameCharPolicy::IsValidChar(validChars[i]));
2142     }
2143
2144     // Non alpha-numeric chars
2145     for (unsigned char c = 0; c < 48; c++)
2146     {
2147         BOOST_CHECK(!arm::pipe::SwTraceNameCharPolicy::IsValidChar(c));
2148     }
2149     for (unsigned char c = 58; c < 65; c++)
2150     {
2151         BOOST_CHECK(!arm::pipe::SwTraceNameCharPolicy::IsValidChar(c));
2152     }
2153     for (unsigned char c = 91; c < 95; c++)
2154     {
2155         BOOST_CHECK(!arm::pipe::SwTraceNameCharPolicy::IsValidChar(c));
2156     }
2157     for (unsigned char c = 96; c < 97; c++)
2158     {
2159         BOOST_CHECK(!arm::pipe::SwTraceNameCharPolicy::IsValidChar(c));
2160     }
2161     for (unsigned char c = 123; c < 128; c++)
2162     {
2163         BOOST_CHECK(!arm::pipe::SwTraceNameCharPolicy::IsValidChar(c));
2164     }
2165
2166     // Not ASCII
2167     for (unsigned char c = 255; c >= 128; c++)
2168     {
2169         BOOST_CHECK(!arm::pipe::SwTraceNameCharPolicy::IsValidChar(c));
2170     }
2171 }
2172
2173 BOOST_AUTO_TEST_CASE(IsValidSwTraceStringTest)
2174 {
2175     // Valid SWTrace strings
2176     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>(""));
2177     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("_"));
2178     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("0123"));
2179     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("valid_string"));
2180     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("VALID_string_456"));
2181     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>(" "));
2182     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("valid string"));
2183     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("!$%"));
2184     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("valid|\\~string#123"));
2185
2186     // Invalid SWTrace strings
2187     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("€£"));
2188     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("invalid‡string"));
2189     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>("12Ž34"));
2190 }
2191
2192 BOOST_AUTO_TEST_CASE(IsValidSwTraceNameStringTest)
2193 {
2194     // Valid SWTrace name strings
2195     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>(""));
2196     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("_"));
2197     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("0123"));
2198     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("valid_string"));
2199     BOOST_CHECK(arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("VALID_string_456"));
2200
2201     // Invalid SWTrace name strings
2202     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>(" "));
2203     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("invalid string"));
2204     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("!$%"));
2205     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("invalid|\\~string#123"));
2206     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("€£"));
2207     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("invalid‡string"));
2208     BOOST_CHECK(!arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>("12Ž34"));
2209 }
2210
2211 template <typename SwTracePolicy>
2212 void StringToSwTraceStringTestHelper(const std::string& testString, std::vector<uint32_t> buffer, size_t expectedSize)
2213 {
2214     // Convert the test string to a SWTrace string
2215     BOOST_CHECK(arm::pipe::StringToSwTraceString<SwTracePolicy>(testString, buffer));
2216
2217     // The buffer must contain at least the length of the string
2218     BOOST_CHECK(!buffer.empty());
2219
2220     // The buffer must be of the expected size (in words)
2221     BOOST_CHECK(buffer.size() == expectedSize);
2222
2223     // The first word of the byte must be the length of the string including the null-terminator
2224     BOOST_CHECK(buffer[0] == testString.size() + 1);
2225
2226     // The contents of the buffer must match the test string
2227     BOOST_CHECK(std::memcmp(testString.data(), buffer.data() + 1, testString.size()) == 0);
2228
2229     // The buffer must include the null-terminator at the end of the string
2230     size_t nullTerminatorIndex = sizeof(uint32_t) + testString.size();
2231     BOOST_CHECK(reinterpret_cast<unsigned char*>(buffer.data())[nullTerminatorIndex] == '\0');
2232 }
2233
2234 BOOST_AUTO_TEST_CASE(StringToSwTraceStringTest)
2235 {
2236     std::vector<uint32_t> buffer;
2237
2238     // Valid SWTrace strings (expected size in words)
2239     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("", buffer, 2);
2240     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("_", buffer, 2);
2241     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("0123", buffer, 3);
2242     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("valid_string", buffer, 5);
2243     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("VALID_string_456", buffer, 6);
2244     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>(" ", buffer, 2);
2245     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("valid string", buffer, 5);
2246     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("!$%", buffer, 2);
2247     StringToSwTraceStringTestHelper<arm::pipe::SwTraceCharPolicy>("valid|\\~string#123", buffer, 6);
2248
2249     // Invalid SWTrace strings
2250     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>("€£", buffer));
2251     BOOST_CHECK(buffer.empty());
2252     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>("invalid‡string", buffer));
2253     BOOST_CHECK(buffer.empty());
2254     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>("12Ž34", buffer));
2255     BOOST_CHECK(buffer.empty());
2256 }
2257
2258 BOOST_AUTO_TEST_CASE(StringToSwTraceNameStringTest)
2259 {
2260     std::vector<uint32_t> buffer;
2261
2262     // Valid SWTrace namestrings (expected size in words)
2263     StringToSwTraceStringTestHelper<arm::pipe::SwTraceNameCharPolicy>("", buffer, 2);
2264     StringToSwTraceStringTestHelper<arm::pipe::SwTraceNameCharPolicy>("_", buffer, 2);
2265     StringToSwTraceStringTestHelper<arm::pipe::SwTraceNameCharPolicy>("0123", buffer, 3);
2266     StringToSwTraceStringTestHelper<arm::pipe::SwTraceNameCharPolicy>("valid_string", buffer, 5);
2267     StringToSwTraceStringTestHelper<arm::pipe::SwTraceNameCharPolicy>("VALID_string_456", buffer, 6);
2268
2269     // Invalid SWTrace namestrings
2270     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>(" ", buffer));
2271     BOOST_CHECK(buffer.empty());
2272     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>("invalid string", buffer));
2273     BOOST_CHECK(buffer.empty());
2274     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>("!$%", buffer));
2275     BOOST_CHECK(buffer.empty());
2276     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>("invalid|\\~string#123", buffer));
2277     BOOST_CHECK(buffer.empty());
2278     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>("€£", buffer));
2279     BOOST_CHECK(buffer.empty());
2280     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>("invalid‡string", buffer));
2281     BOOST_CHECK(buffer.empty());
2282     BOOST_CHECK(!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>("12Ž34", buffer));
2283     BOOST_CHECK(buffer.empty());
2284 }
2285
2286 BOOST_AUTO_TEST_CASE(CheckPeriodicCounterCaptureThread)
2287 {
2288     class CaptureReader : public IReadCounterValues
2289     {
2290     public:
2291         CaptureReader(uint16_t counterSize)
2292         {
2293             for (uint16_t i = 0; i < counterSize; ++i)
2294             {
2295                 m_Data[i] = 0;
2296             }
2297             m_CounterSize = counterSize;
2298         }
2299         //not used
2300         bool IsCounterRegistered(uint16_t counterUid) const override
2301         {
2302             armnn::IgnoreUnused(counterUid);
2303             return false;
2304         }
2305
2306         uint16_t GetCounterCount() const override
2307         {
2308             return m_CounterSize;
2309         }
2310
2311         uint32_t GetAbsoluteCounterValue(uint16_t counterUid) const override
2312         {
2313             if (counterUid > m_CounterSize)
2314             {
2315                 BOOST_FAIL("Invalid counter Uid");
2316             }
2317             return m_Data.at(counterUid).load();
2318         }
2319
2320         uint32_t GetDeltaCounterValue(uint16_t counterUid)  override
2321         {
2322             if (counterUid > m_CounterSize)
2323             {
2324                 BOOST_FAIL("Invalid counter Uid");
2325             }
2326             return m_Data.at(counterUid).load();
2327         }
2328
2329         void SetCounterValue(uint16_t counterUid, uint32_t value)
2330         {
2331             if (counterUid > m_CounterSize)
2332             {
2333                 BOOST_FAIL("Invalid counter Uid");
2334             }
2335             m_Data.at(counterUid).store(value);
2336         }
2337
2338     private:
2339         std::unordered_map<uint16_t, std::atomic<uint32_t>> m_Data;
2340         uint16_t m_CounterSize;
2341     };
2342
2343     ProfilingStateMachine profilingStateMachine;
2344
2345     const std::unordered_map<armnn::BackendId,
2346             std::shared_ptr<armnn::profiling::IBackendProfilingContext>> backendProfilingContext;
2347     CounterIdMap counterIdMap;
2348     Holder data;
2349     std::vector<uint16_t> captureIds1 = { 0, 1 };
2350     std::vector<uint16_t> captureIds2;
2351
2352     MockBufferManager mockBuffer(512);
2353     SendCounterPacket sendCounterPacket(mockBuffer);
2354     SendThread sendThread(profilingStateMachine, mockBuffer, sendCounterPacket);
2355
2356     std::vector<uint16_t> counterIds;
2357     CaptureReader captureReader(2);
2358
2359     unsigned int valueA   = 10;
2360     unsigned int valueB   = 15;
2361     unsigned int numSteps = 5;
2362
2363     PeriodicCounterCapture periodicCounterCapture(std::ref(data), std::ref(sendCounterPacket), captureReader,
2364                                                   counterIdMap, backendProfilingContext);
2365
2366     for (unsigned int i = 0; i < numSteps; ++i)
2367     {
2368         data.SetCaptureData(1, captureIds1, {});
2369         captureReader.SetCounterValue(0, valueA * (i + 1));
2370         captureReader.SetCounterValue(1, valueB * (i + 1));
2371
2372         periodicCounterCapture.Start();
2373         periodicCounterCapture.Stop();
2374     }
2375
2376     auto buffer = mockBuffer.GetReadableBuffer();
2377
2378     uint32_t headerWord0 = ReadUint32(buffer, 0);
2379     uint32_t headerWord1 = ReadUint32(buffer, 4);
2380
2381     BOOST_TEST(((headerWord0 >> 26) & 0x0000003F) == 3);    // packet family
2382     BOOST_TEST(((headerWord0 >> 19) & 0x0000007F) == 0);    // packet class
2383     BOOST_TEST(((headerWord0 >> 16) & 0x00000007) == 0);    // packet type
2384     BOOST_TEST(headerWord1 == 20);
2385
2386     uint32_t offset    = 16;
2387     uint16_t readIndex = ReadUint16(buffer, offset);
2388     BOOST_TEST(0 == readIndex);
2389
2390     offset += 2;
2391     uint32_t readValue = ReadUint32(buffer, offset);
2392     BOOST_TEST((valueA * numSteps) == readValue);
2393
2394     offset += 4;
2395     readIndex = ReadUint16(buffer, offset);
2396     BOOST_TEST(1 == readIndex);
2397
2398     offset += 2;
2399     readValue = ReadUint32(buffer, offset);
2400     BOOST_TEST((valueB * numSteps) == readValue);
2401 }
2402
2403 BOOST_AUTO_TEST_CASE(RequestCounterDirectoryCommandHandlerTest1)
2404 {
2405     const uint32_t familyId = 0;
2406     const uint32_t packetId = 3;
2407     const uint32_t version  = 1;
2408     ProfilingStateMachine profilingStateMachine;
2409     CounterDirectory counterDirectory;
2410     MockBufferManager mockBuffer1(1024);
2411     SendCounterPacket sendCounterPacket(mockBuffer1);
2412     SendThread sendThread(profilingStateMachine, mockBuffer1, sendCounterPacket);
2413     MockBufferManager mockBuffer2(1024);
2414     SendTimelinePacket sendTimelinePacket(mockBuffer2);
2415     RequestCounterDirectoryCommandHandler commandHandler(familyId, packetId, version, counterDirectory,
2416                                                          sendCounterPacket, sendTimelinePacket, profilingStateMachine);
2417
2418     const uint32_t wrongPacketId = 47;
2419     const uint32_t wrongHeader   = (wrongPacketId & 0x000003FF) << 16;
2420
2421     arm::pipe::Packet wrongPacket(wrongHeader);
2422
2423     profilingStateMachine.TransitionToState(ProfilingState::Uninitialised);
2424     BOOST_CHECK_THROW(commandHandler(wrongPacket), armnn::RuntimeException); // Wrong profiling state
2425     profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
2426     BOOST_CHECK_THROW(commandHandler(wrongPacket), armnn::RuntimeException); // Wrong profiling state
2427     profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
2428     BOOST_CHECK_THROW(commandHandler(wrongPacket), armnn::RuntimeException); // Wrong profiling state
2429     profilingStateMachine.TransitionToState(ProfilingState::Active);
2430     BOOST_CHECK_THROW(commandHandler(wrongPacket), armnn::InvalidArgumentException); // Wrong packet
2431
2432     const uint32_t rightHeader = (packetId & 0x000003FF) << 16;
2433
2434     arm::pipe::Packet rightPacket(rightHeader);
2435
2436     BOOST_CHECK_NO_THROW(commandHandler(rightPacket)); // Right packet
2437
2438     auto readBuffer1 = mockBuffer1.GetReadableBuffer();
2439
2440     uint32_t header1Word0 = ReadUint32(readBuffer1, 0);
2441     uint32_t header1Word1 = ReadUint32(readBuffer1, 4);
2442
2443     // Counter directory packet
2444     BOOST_TEST(((header1Word0 >> 26) & 0x0000003F) == 0); // packet family
2445     BOOST_TEST(((header1Word0 >> 16) & 0x000003FF) == 2); // packet id
2446     BOOST_TEST(header1Word1 == 24);                       // data length
2447
2448     uint32_t bodyHeader1Word0   = ReadUint32(readBuffer1, 8);
2449     uint16_t deviceRecordCount = armnn::numeric_cast<uint16_t>(bodyHeader1Word0 >> 16);
2450     BOOST_TEST(deviceRecordCount == 0); // device_records_count
2451
2452     auto readBuffer2 = mockBuffer2.GetReadableBuffer();
2453
2454     uint32_t header2Word0 = ReadUint32(readBuffer2, 0);
2455     uint32_t header2Word1 = ReadUint32(readBuffer2, 4);
2456
2457     // Timeline message directory packet
2458     BOOST_TEST(((header2Word0 >> 26) & 0x0000003F) == 1); // packet family
2459     BOOST_TEST(((header2Word0 >> 16) & 0x000003FF) == 0); // packet id
2460     BOOST_TEST(header2Word1 == 443);                      // data length
2461 }
2462
2463 BOOST_AUTO_TEST_CASE(RequestCounterDirectoryCommandHandlerTest2)
2464 {
2465     const uint32_t familyId = 0;
2466     const uint32_t packetId = 3;
2467     const uint32_t version  = 1;
2468     ProfilingStateMachine profilingStateMachine;
2469     CounterDirectory counterDirectory;
2470     MockBufferManager mockBuffer1(1024);
2471     SendCounterPacket sendCounterPacket(mockBuffer1);
2472     SendThread sendThread(profilingStateMachine, mockBuffer1, sendCounterPacket);
2473     MockBufferManager mockBuffer2(1024);
2474     SendTimelinePacket sendTimelinePacket(mockBuffer2);
2475     RequestCounterDirectoryCommandHandler commandHandler(familyId, packetId, version, counterDirectory,
2476                                                          sendCounterPacket, sendTimelinePacket, profilingStateMachine);
2477     const uint32_t header = (packetId & 0x000003FF) << 16;
2478     const arm::pipe::Packet packet(header);
2479
2480     const Device* device = counterDirectory.RegisterDevice("deviceA", 1);
2481     BOOST_CHECK(device != nullptr);
2482     const CounterSet* counterSet = counterDirectory.RegisterCounterSet("countersetA");
2483     BOOST_CHECK(counterSet != nullptr);
2484     counterDirectory.RegisterCategory("categoryA");
2485     counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID, 24,
2486                                      "categoryA", 0, 1, 2.0f, "counterA", "descA");
2487     counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID, 25,
2488                                      "categoryA", 1, 1, 3.0f, "counterB", "descB");
2489
2490     profilingStateMachine.TransitionToState(ProfilingState::Uninitialised);
2491     BOOST_CHECK_THROW(commandHandler(packet), armnn::RuntimeException);    // Wrong profiling state
2492     profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
2493     BOOST_CHECK_THROW(commandHandler(packet), armnn::RuntimeException);    // Wrong profiling state
2494     profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
2495     BOOST_CHECK_THROW(commandHandler(packet), armnn::RuntimeException);    // Wrong profiling state
2496     profilingStateMachine.TransitionToState(ProfilingState::Active);
2497     BOOST_CHECK_NO_THROW(commandHandler(packet));
2498
2499     auto readBuffer1 = mockBuffer1.GetReadableBuffer();
2500
2501     const uint32_t header1Word0 = ReadUint32(readBuffer1, 0);
2502     const uint32_t header1Word1 = ReadUint32(readBuffer1, 4);
2503
2504     BOOST_TEST(((header1Word0 >> 26) & 0x0000003F) == 0); // packet family
2505     BOOST_TEST(((header1Word0 >> 16) & 0x000003FF) == 2); // packet id
2506     BOOST_TEST(header1Word1 == 236);                      // data length
2507
2508     const uint32_t bodyHeaderSizeBytes = bodyHeaderSize * sizeof(uint32_t);
2509
2510     const uint32_t bodyHeader1Word0      = ReadUint32(readBuffer1, 8);
2511     const uint32_t bodyHeader1Word1      = ReadUint32(readBuffer1, 12);
2512     const uint32_t bodyHeader1Word2      = ReadUint32(readBuffer1, 16);
2513     const uint32_t bodyHeader1Word3      = ReadUint32(readBuffer1, 20);
2514     const uint32_t bodyHeader1Word4      = ReadUint32(readBuffer1, 24);
2515     const uint32_t bodyHeader1Word5      = ReadUint32(readBuffer1, 28);
2516     const uint16_t deviceRecordCount     = armnn::numeric_cast<uint16_t>(bodyHeader1Word0 >> 16);
2517     const uint16_t counterSetRecordCount = armnn::numeric_cast<uint16_t>(bodyHeader1Word2 >> 16);
2518     const uint16_t categoryRecordCount   = armnn::numeric_cast<uint16_t>(bodyHeader1Word4 >> 16);
2519     BOOST_TEST(deviceRecordCount == 1);                      // device_records_count
2520     BOOST_TEST(bodyHeader1Word1 == 0 + bodyHeaderSizeBytes);      // device_records_pointer_table_offset
2521     BOOST_TEST(counterSetRecordCount == 1);                  // counter_set_count
2522     BOOST_TEST(bodyHeader1Word3 == 4 + bodyHeaderSizeBytes);      // counter_set_pointer_table_offset
2523     BOOST_TEST(categoryRecordCount == 1);                    // categories_count
2524     BOOST_TEST(bodyHeader1Word5 == 8 + bodyHeaderSizeBytes);      // categories_pointer_table_offset
2525
2526     const uint32_t deviceRecordOffset = ReadUint32(readBuffer1, 32);
2527     BOOST_TEST(deviceRecordOffset == 12);
2528
2529     const uint32_t counterSetRecordOffset = ReadUint32(readBuffer1, 36);
2530     BOOST_TEST(counterSetRecordOffset == 28);
2531
2532     const uint32_t categoryRecordOffset = ReadUint32(readBuffer1, 40);
2533     BOOST_TEST(categoryRecordOffset == 48);
2534
2535     auto readBuffer2 = mockBuffer2.GetReadableBuffer();
2536
2537     const uint32_t header2Word0 = ReadUint32(readBuffer2, 0);
2538     const uint32_t header2Word1 = ReadUint32(readBuffer2, 4);
2539
2540     // Timeline message directory packet
2541     BOOST_TEST(((header2Word0 >> 26) & 0x0000003F) == 1); // packet family
2542     BOOST_TEST(((header2Word0 >> 16) & 0x000003FF) == 0); // packet id
2543     BOOST_TEST(header2Word1 == 443);                      // data length
2544 }
2545
2546 BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodConnectionAcknowledgedPacket)
2547 {
2548     unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2549
2550     // Reset the profiling service to the uninitialized state
2551     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
2552     options.m_EnableProfiling          = true;
2553     armnn::profiling::ProfilingService profilingService;
2554     profilingService.ResetExternalProfilingOptions(options, true);
2555
2556     // Swap the profiling connection factory in the profiling service instance with our mock one
2557     SwapProfilingConnectionFactoryHelper helper(profilingService);
2558
2559     // Bring the profiling service to the "WaitingForAck" state
2560     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
2561     profilingService.Update();    // Initialize the counter directory
2562     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
2563     profilingService.Update();    // Create the profiling connection
2564
2565     // Get the mock profiling connection
2566     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
2567     BOOST_CHECK(mockProfilingConnection);
2568
2569     // Remove the packets received so far
2570     mockProfilingConnection->Clear();
2571
2572     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
2573     profilingService.Update();    // Start the command handler and the send thread
2574
2575     // Wait for the Stream Metadata packet to be sent
2576     BOOST_CHECK(helper.WaitForPacketsSent(
2577             mockProfilingConnection, PacketType::StreamMetaData, streamMetadataPacketsize) >= 1);
2578
2579     // Write a valid "Connection Acknowledged" packet into the mock profiling connection, to simulate a valid
2580     // reply from an external profiling service
2581
2582     // Connection Acknowledged Packet header (word 0, word 1 is always zero):
2583     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
2584     // 16:25 [10] packet_id: Packet identifier, value 0b0000000001
2585     // 8:15  [8]  reserved: Reserved, value 0b00000000
2586     // 0:7   [8]  reserved: Reserved, value 0b00000000
2587     uint32_t packetFamily = 0;
2588     uint32_t packetId     = 1;
2589     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
2590
2591     // Create the Connection Acknowledged Packet
2592     arm::pipe::Packet connectionAcknowledgedPacket(header);
2593
2594     // Write the packet to the mock profiling connection
2595     mockProfilingConnection->WritePacket(std::move(connectionAcknowledgedPacket));
2596
2597     // Wait for the counter directory packet to ensure the ConnectionAcknowledgedCommandHandler has run.
2598     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::CounterDirectory) == 1);
2599
2600     // The Connection Acknowledged Command Handler should have updated the profiling state accordingly
2601     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2602
2603     // Reset the profiling service to stop any running thread
2604     options.m_EnableProfiling = false;
2605     profilingService.ResetExternalProfilingOptions(options, true);
2606 }
2607
2608 BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodRequestCounterDirectoryPacket)
2609 {
2610     // Reset the profiling service to the uninitialized state
2611     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
2612     options.m_EnableProfiling          = true;
2613     armnn::profiling::ProfilingService profilingService;
2614     profilingService.ResetExternalProfilingOptions(options, true);
2615
2616     // Swap the profiling connection factory in the profiling service instance with our mock one
2617     SwapProfilingConnectionFactoryHelper helper(profilingService);
2618
2619     // Bring the profiling service to the "Active" state
2620     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
2621     profilingService.Update();    // Initialize the counter directory
2622     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
2623     profilingService.Update();    // Create the profiling connection
2624     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
2625     profilingService.Update();    // Start the command handler and the send thread
2626
2627     // Get the mock profiling connection
2628     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
2629     BOOST_CHECK(mockProfilingConnection);
2630
2631     // Force the profiling service to the "Active" state
2632     helper.ForceTransitionToState(ProfilingState::Active);
2633     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2634
2635     // Write a valid "Request Counter Directory" packet into the mock profiling connection, to simulate a valid
2636     // reply from an external profiling service
2637
2638     // Request Counter Directory packet header (word 0, word 1 is always zero):
2639     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
2640     // 16:25 [10] packet_id: Packet identifier, value 0b0000000011
2641     // 8:15  [8]  reserved: Reserved, value 0b00000000
2642     // 0:7   [8]  reserved: Reserved, value 0b00000000
2643     uint32_t packetFamily = 0;
2644     uint32_t packetId     = 3;
2645     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
2646
2647     // Create the Request Counter Directory packet
2648     arm::pipe::Packet requestCounterDirectoryPacket(header);
2649
2650     // Write the packet to the mock profiling connection
2651     mockProfilingConnection->WritePacket(std::move(requestCounterDirectoryPacket));
2652
2653     // Expecting one CounterDirectory Packet of length 652
2654     // and one TimelineMessageDirectory packet of length 451
2655     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::CounterDirectory, 652) == 1);
2656     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::TimelineMessageDirectory, 451) == 1);
2657
2658     // The Request Counter Directory Command Handler should not have updated the profiling state
2659     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2660
2661     // Reset the profiling service to stop any running thread
2662     options.m_EnableProfiling = false;
2663     profilingService.ResetExternalProfilingOptions(options, true);
2664 }
2665
2666 BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInvalidCounterUid)
2667 {
2668     // Reset the profiling service to the uninitialized state
2669     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
2670     options.m_EnableProfiling          = true;
2671     armnn::profiling::ProfilingService profilingService;
2672     profilingService.ResetExternalProfilingOptions(options, true);
2673
2674     // Swap the profiling connection factory in the profiling service instance with our mock one
2675     SwapProfilingConnectionFactoryHelper helper(profilingService);
2676
2677     // Bring the profiling service to the "Active" state
2678     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
2679     profilingService.Update();    // Initialize the counter directory
2680     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
2681     profilingService.Update();    // Create the profiling connection
2682     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
2683     profilingService.Update();    // Start the command handler and the send thread
2684
2685     // Get the mock profiling connection
2686     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
2687     BOOST_CHECK(mockProfilingConnection);
2688
2689     // Force the profiling service to the "Active" state
2690     helper.ForceTransitionToState(ProfilingState::Active);
2691     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2692
2693     // Remove the packets received so far
2694     mockProfilingConnection->Clear();
2695
2696     // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
2697     // external profiling service
2698
2699     // Periodic Counter Selection packet header:
2700     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
2701     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
2702     // 8:15  [8]  reserved: Reserved, value 0b00000000
2703     // 0:7   [8]  reserved: Reserved, value 0b00000000
2704     uint32_t packetFamily = 0;
2705     uint32_t packetId     = 4;
2706     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
2707
2708     uint32_t capturePeriod = 123456;    // Some capture period (microseconds)
2709
2710     // Get the first valid counter UID
2711     const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
2712     const Counters& counters                  = counterDirectory.GetCounters();
2713     BOOST_CHECK(counters.size() > 1);
2714     uint16_t counterUidA = counters.begin()->first;    // First valid counter UID
2715     uint16_t counterUidB = 9999;                       // Second invalid counter UID
2716
2717     uint32_t length = 8;
2718
2719     auto data = std::make_unique<unsigned char[]>(length);
2720     WriteUint32(data.get(), 0, capturePeriod);
2721     WriteUint16(data.get(), 4, counterUidA);
2722     WriteUint16(data.get(), 6, counterUidB);
2723
2724     // Create the Periodic Counter Selection packet
2725     // Length > 0, this will start the Period Counter Capture thread
2726     arm::pipe::Packet periodicCounterSelectionPacket(header, length, data);
2727
2728
2729     // Write the packet to the mock profiling connection
2730     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
2731
2732     // Expecting one Periodic Counter Selection packet of length 14
2733     // and at least one Periodic Counter Capture packet of length 22
2734     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterSelection, 14) == 1);
2735     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterCapture, 22) >= 1);
2736
2737     // The Periodic Counter Selection Handler should not have updated the profiling state
2738     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2739
2740     // Reset the profiling service to stop any running thread
2741     options.m_EnableProfiling = false;
2742     profilingService.ResetExternalProfilingOptions(options, true);
2743 }
2744
2745 BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketNoCounters)
2746 {
2747     // Reset the profiling service to the uninitialized state
2748     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
2749     options.m_EnableProfiling          = true;
2750     armnn::profiling::ProfilingService profilingService;
2751     profilingService.ResetExternalProfilingOptions(options, true);
2752
2753     // Swap the profiling connection factory in the profiling service instance with our mock one
2754     SwapProfilingConnectionFactoryHelper helper(profilingService);
2755
2756     // Bring the profiling service to the "Active" state
2757     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
2758     profilingService.Update();    // Initialize the counter directory
2759     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
2760     profilingService.Update();    // Create the profiling connection
2761     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
2762     profilingService.Update();    // Start the command handler and the send thread
2763
2764     // Get the mock profiling connection
2765     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
2766     BOOST_CHECK(mockProfilingConnection);
2767
2768     // Wait for the Stream Metadata packet the be sent
2769     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
2770     helper.WaitForPacketsSent(mockProfilingConnection, PacketType::StreamMetaData);
2771
2772     // Force the profiling service to the "Active" state
2773     helper.ForceTransitionToState(ProfilingState::Active);
2774     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2775
2776     // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
2777     // external profiling service
2778
2779     // Periodic Counter Selection packet header:
2780     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
2781     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
2782     // 8:15  [8]  reserved: Reserved, value 0b00000000
2783     // 0:7   [8]  reserved: Reserved, value 0b00000000
2784     uint32_t packetFamily = 0;
2785     uint32_t packetId     = 4;
2786     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
2787
2788     // Create the Periodic Counter Selection packet
2789     // Length == 0, this will disable the collection of counters
2790     arm::pipe::Packet periodicCounterSelectionPacket(header);
2791
2792     // Write the packet to the mock profiling connection
2793     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
2794
2795     // Wait for the Periodic Counter Selection packet of length 12 to be sent
2796     // The size of the expected Periodic Counter Selection (echos the sent one)
2797     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterSelection, 12) == 1);
2798
2799     // The Periodic Counter Selection Handler should not have updated the profiling state
2800     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2801
2802     // No Periodic Counter packets are expected
2803     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterCapture, 0, 0) == 0);
2804
2805     // Reset the profiling service to stop any running thread
2806     options.m_EnableProfiling = false;
2807     profilingService.ResetExternalProfilingOptions(options, true);
2808 }
2809
2810 BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketSingleCounter)
2811 {
2812     // Reset the profiling service to the uninitialized state
2813     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
2814     options.m_EnableProfiling          = true;
2815     armnn::profiling::ProfilingService profilingService;
2816     profilingService.ResetExternalProfilingOptions(options, true);
2817
2818     // Swap the profiling connection factory in the profiling service instance with our mock one
2819     SwapProfilingConnectionFactoryHelper helper(profilingService);
2820
2821     // Bring the profiling service to the "Active" state
2822     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
2823     profilingService.Update();    // Initialize the counter directory
2824     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
2825     profilingService.Update();    // Create the profiling connection
2826     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
2827     profilingService.Update();    // Start the command handler and the send thread
2828
2829     // Get the mock profiling connection
2830     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
2831     BOOST_CHECK(mockProfilingConnection);
2832
2833     // Wait for the Stream Metadata packet to be sent
2834     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
2835     helper.WaitForPacketsSent(mockProfilingConnection, PacketType::StreamMetaData);
2836
2837     // Force the profiling service to the "Active" state
2838     helper.ForceTransitionToState(ProfilingState::Active);
2839     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2840
2841     // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
2842     // external profiling service
2843
2844     // Periodic Counter Selection packet header:
2845     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
2846     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
2847     // 8:15  [8]  reserved: Reserved, value 0b00000000
2848     // 0:7   [8]  reserved: Reserved, value 0b00000000
2849     uint32_t packetFamily = 0;
2850     uint32_t packetId     = 4;
2851     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
2852
2853     uint32_t capturePeriod = 123456;    // Some capture period (microseconds)
2854
2855     // Get the first valid counter UID
2856     const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
2857     const Counters& counters                  = counterDirectory.GetCounters();
2858     BOOST_CHECK(!counters.empty());
2859     uint16_t counterUid = counters.begin()->first;    // Valid counter UID
2860
2861     uint32_t length = 6;
2862
2863     auto data = std::make_unique<unsigned char[]>(length);
2864     WriteUint32(data.get(), 0, capturePeriod);
2865     WriteUint16(data.get(), 4, counterUid);
2866
2867     // Create the Periodic Counter Selection packet
2868     // Length > 0, this will start the Period Counter Capture thread
2869     arm::pipe::Packet periodicCounterSelectionPacket(header, length, data);
2870
2871     // Write the packet to the mock profiling connection
2872     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
2873
2874     // Expecting one Periodic Counter Selection packet of length 14
2875     // and at least one Periodic Counter Capture packet of length 22
2876     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterSelection, 14) == 1);
2877     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterCapture, 22) >= 1);
2878
2879     // The Periodic Counter Selection Handler should not have updated the profiling state
2880     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2881
2882     // Reset the profiling service to stop any running thread
2883     options.m_EnableProfiling = false;
2884     profilingService.ResetExternalProfilingOptions(options, true);
2885 }
2886
2887 BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketMultipleCounters)
2888 {
2889     // Reset the profiling service to the uninitialized state
2890     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
2891     options.m_EnableProfiling          = true;
2892     armnn::profiling::ProfilingService profilingService;
2893     profilingService.ResetExternalProfilingOptions(options, true);
2894
2895     // Swap the profiling connection factory in the profiling service instance with our mock one
2896     SwapProfilingConnectionFactoryHelper helper(profilingService);
2897
2898     // Bring the profiling service to the "Active" state
2899     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
2900     profilingService.Update();    // Initialize the counter directory
2901     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
2902     profilingService.Update();    // Create the profiling connection
2903     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
2904     profilingService.Update();    // Start the command handler and the send thread
2905
2906     // Get the mock profiling connection
2907     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
2908     BOOST_CHECK(mockProfilingConnection);
2909
2910     // Wait for the Stream Metadata packet the be sent
2911     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
2912     helper.WaitForPacketsSent(mockProfilingConnection, PacketType::StreamMetaData);
2913
2914     // Force the profiling service to the "Active" state
2915     helper.ForceTransitionToState(ProfilingState::Active);
2916     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2917
2918     // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
2919     // external profiling service
2920
2921     // Periodic Counter Selection packet header:
2922     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
2923     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
2924     // 8:15  [8]  reserved: Reserved, value 0b00000000
2925     // 0:7   [8]  reserved: Reserved, value 0b00000000
2926     uint32_t packetFamily = 0;
2927     uint32_t packetId     = 4;
2928     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
2929
2930     uint32_t capturePeriod = 123456;    // Some capture period (microseconds)
2931
2932     // Get the first valid counter UID
2933     const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
2934     const Counters& counters                  = counterDirectory.GetCounters();
2935     BOOST_CHECK(counters.size() > 1);
2936     uint16_t counterUidA = counters.begin()->first;        // First valid counter UID
2937     uint16_t counterUidB = (counters.begin()++)->first;    // Second valid counter UID
2938
2939     uint32_t length = 8;
2940
2941     auto data = std::make_unique<unsigned char[]>(length);
2942     WriteUint32(data.get(), 0, capturePeriod);
2943     WriteUint16(data.get(), 4, counterUidA);
2944     WriteUint16(data.get(), 6, counterUidB);
2945
2946     // Create the Periodic Counter Selection packet
2947     // Length > 0, this will start the Period Counter Capture thread
2948     arm::pipe::Packet periodicCounterSelectionPacket(header, length, data);
2949
2950     // Write the packet to the mock profiling connection
2951     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
2952
2953     // Expecting one PeriodicCounterSelection Packet with a length of 16
2954     // And at least one PeriodicCounterCapture Packet with a length of 28
2955     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterSelection, 16) == 1);
2956     BOOST_CHECK(helper.WaitForPacketsSent(mockProfilingConnection, PacketType::PeriodicCounterCapture, 28) >= 1);
2957
2958     // The Periodic Counter Selection Handler should not have updated the profiling state
2959     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
2960
2961     // Reset the profiling service to stop any running thread
2962     options.m_EnableProfiling = false;
2963     profilingService.ResetExternalProfilingOptions(options, true);
2964 }
2965
2966 BOOST_AUTO_TEST_CASE(CheckProfilingServiceDisconnect)
2967 {
2968     // Reset the profiling service to the uninitialized state
2969     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
2970     options.m_EnableProfiling          = true;
2971     armnn::profiling::ProfilingService profilingService;
2972     profilingService.ResetExternalProfilingOptions(options, true);
2973
2974     // Swap the profiling connection factory in the profiling service instance with our mock one
2975     SwapProfilingConnectionFactoryHelper helper(profilingService);
2976
2977     // Try to disconnect the profiling service while in the "Uninitialised" state
2978     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
2979     profilingService.Disconnect();
2980     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);    // The state should not change
2981
2982     // Try to disconnect the profiling service while in the "NotConnected" state
2983     profilingService.Update();    // Initialize the counter directory
2984     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
2985     profilingService.Disconnect();
2986     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);    // The state should not change
2987
2988     // Try to disconnect the profiling service while in the "WaitingForAck" state
2989     profilingService.Update();    // Create the profiling connection
2990     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
2991     profilingService.Disconnect();
2992     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);    // The state should not change
2993
2994     // Try to disconnect the profiling service while in the "Active" state
2995     profilingService.Update();    // Start the command handler and the send thread
2996
2997     // Get the mock profiling connection
2998     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
2999     BOOST_CHECK(mockProfilingConnection);
3000
3001     // Wait for the Stream Metadata packet the be sent
3002     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
3003     helper.WaitForPacketsSent(mockProfilingConnection, PacketType::StreamMetaData);
3004
3005     // Force the profiling service to the "Active" state
3006     helper.ForceTransitionToState(ProfilingState::Active);
3007     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
3008
3009     // Check that the profiling connection is open
3010     BOOST_CHECK(mockProfilingConnection->IsOpen());
3011
3012     profilingService.Disconnect();
3013     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);   // The state should have changed
3014
3015     // Check that the profiling connection has been reset
3016     mockProfilingConnection = helper.GetMockProfilingConnection();
3017     BOOST_CHECK(mockProfilingConnection == nullptr);
3018
3019     // Reset the profiling service to stop any running thread
3020     options.m_EnableProfiling = false;
3021     profilingService.ResetExternalProfilingOptions(options, true);
3022 }
3023
3024 BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPerJobCounterSelectionPacket)
3025 {
3026     // Reset the profiling service to the uninitialized state
3027     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3028     options.m_EnableProfiling          = true;
3029     armnn::profiling::ProfilingService profilingService;
3030     profilingService.ResetExternalProfilingOptions(options, true);
3031
3032     // Swap the profiling connection factory in the profiling service instance with our mock one
3033     SwapProfilingConnectionFactoryHelper helper(profilingService);
3034
3035     // Bring the profiling service to the "Active" state
3036     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3037     profilingService.Update();    // Initialize the counter directory
3038     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
3039     profilingService.Update();    // Create the profiling connection
3040     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
3041     profilingService.Update();    // Start the command handler and the send thread
3042
3043     // Get the mock profiling connection
3044     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
3045     BOOST_CHECK(mockProfilingConnection);
3046
3047     // Wait for the Stream Metadata packet the be sent
3048     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
3049     helper.WaitForPacketsSent(mockProfilingConnection, PacketType::StreamMetaData);
3050
3051     // Force the profiling service to the "Active" state
3052     helper.ForceTransitionToState(ProfilingState::Active);
3053     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
3054
3055     // Write a "Per-Job Counter Selection" packet into the mock profiling connection, to simulate an input from an
3056     // external profiling service
3057
3058     // Per-Job Counter Selection packet header:
3059     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
3060     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
3061     // 8:15  [8]  reserved: Reserved, value 0b00000000
3062     // 0:7   [8]  reserved: Reserved, value 0b00000000
3063     uint32_t packetFamily = 0;
3064     uint32_t packetId     = 5;
3065     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
3066
3067     // Create the Per-Job Counter Selection packet
3068     // Length == 0, this will disable the collection of counters
3069     arm::pipe::Packet periodicCounterSelectionPacket(header);
3070
3071     // Write the packet to the mock profiling connection
3072     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
3073
3074     // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
3075     // the Per-Job Counter Selection packet gets processed by the profiling service
3076     std::this_thread::sleep_for(std::chrono::milliseconds(5));
3077
3078     // The Per-Job Counter Selection Command Handler should not have updated the profiling state
3079     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
3080
3081     // The Per-Job Counter Selection packets are dropped silently, so there should be no reply coming
3082     // from the profiling service
3083     const auto StreamMetaDataSize = static_cast<unsigned long>(
3084             helper.WaitForPacketsSent(mockProfilingConnection, PacketType::StreamMetaData, 0, 0));
3085     BOOST_CHECK(StreamMetaDataSize == mockProfilingConnection->GetWrittenDataSize());
3086
3087     // Reset the profiling service to stop any running thread
3088     options.m_EnableProfiling = false;
3089     profilingService.ResetExternalProfilingOptions(options, true);
3090 }
3091
3092 BOOST_AUTO_TEST_CASE(CheckConfigureProfilingServiceOn)
3093 {
3094     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3095     options.m_EnableProfiling          = true;
3096     armnn::profiling::ProfilingService profilingService;
3097     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3098     profilingService.ConfigureProfilingService(options);
3099     // should get as far as NOT_CONNECTED
3100     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
3101     // Reset the profiling service to stop any running thread
3102     options.m_EnableProfiling = false;
3103     profilingService.ResetExternalProfilingOptions(options, true);
3104 }
3105
3106 BOOST_AUTO_TEST_CASE(CheckConfigureProfilingServiceOff)
3107 {
3108     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3109     armnn::profiling::ProfilingService profilingService;
3110     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3111     profilingService.ConfigureProfilingService(options);
3112     // should not move from Uninitialised
3113     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3114     // Reset the profiling service to stop any running thread
3115     options.m_EnableProfiling = false;
3116     profilingService.ResetExternalProfilingOptions(options, true);
3117 }
3118
3119 BOOST_AUTO_TEST_CASE(CheckProfilingServiceEnabled)
3120 {
3121     // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
3122     LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
3123     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3124     options.m_EnableProfiling          = true;
3125     armnn::profiling::ProfilingService profilingService;
3126     profilingService.ResetExternalProfilingOptions(options, true);
3127     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3128     profilingService.Update();
3129     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
3130
3131     // Redirect the output to a local stream so that we can parse the warning message
3132     std::stringstream ss;
3133     StreamRedirector streamRedirector(std::cout, ss.rdbuf());
3134     profilingService.Update();
3135
3136     // Reset the profiling service to stop any running thread
3137     options.m_EnableProfiling = false;
3138     profilingService.ResetExternalProfilingOptions(options, true);
3139
3140     streamRedirector.CancelRedirect();
3141
3142     // Check that the expected error has occurred and logged to the standard output
3143     if (ss.str().find("Cannot connect to stream socket: Connection refused") == std::string::npos)
3144     {
3145         std::cout << ss.str();
3146         BOOST_FAIL("Expected string not found.");
3147     }
3148 }
3149
3150 BOOST_AUTO_TEST_CASE(CheckProfilingServiceEnabledRuntime)
3151 {
3152     // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
3153     LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
3154     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3155     armnn::profiling::ProfilingService profilingService;
3156     profilingService.ResetExternalProfilingOptions(options, true);
3157     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3158     profilingService.Update();
3159     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3160     options.m_EnableProfiling = true;
3161     profilingService.ResetExternalProfilingOptions(options);
3162     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3163     profilingService.Update();
3164     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
3165
3166     // Redirect the output to a local stream so that we can parse the warning message
3167     std::stringstream ss;
3168     StreamRedirector streamRedirector(std::cout, ss.rdbuf());
3169     profilingService.Update();
3170
3171     // Reset the profiling service to stop any running thread
3172     options.m_EnableProfiling = false;
3173     profilingService.ResetExternalProfilingOptions(options, true);
3174
3175     streamRedirector.CancelRedirect();
3176
3177     // Check that the expected error has occurred and logged to the standard output
3178     if (ss.str().find("Cannot connect to stream socket: Connection refused") == std::string::npos)
3179     {
3180         std::cout << ss.str();
3181         BOOST_FAIL("Expected string not found.");
3182     }
3183 }
3184
3185 BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadConnectionAcknowledgedPacket)
3186 {
3187     // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
3188     LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
3189
3190
3191     // Redirect the standard output to a local stream so that we can parse the warning message
3192     std::stringstream ss;
3193     StreamRedirector streamRedirector(std::cout, ss.rdbuf());
3194
3195     // Reset the profiling service to the uninitialized state
3196     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3197     options.m_EnableProfiling          = true;
3198     armnn::profiling::ProfilingService profilingService;
3199     profilingService.ResetExternalProfilingOptions(options, true);
3200
3201     // Swap the profiling connection factory in the profiling service instance with our mock one
3202     SwapProfilingConnectionFactoryHelper helper(profilingService);
3203
3204     // Bring the profiling service to the "WaitingForAck" state
3205     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3206     profilingService.Update();    // Initialize the counter directory
3207     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
3208     profilingService.Update();    // Create the profiling connection
3209
3210     // Get the mock profiling connection
3211     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
3212     BOOST_CHECK(mockProfilingConnection);
3213
3214     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
3215
3216     // Connection Acknowledged Packet header (word 0, word 1 is always zero):
3217     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
3218     // 16:25 [10] packet_id: Packet identifier, value 0b0000000001
3219     // 8:15  [8]  reserved: Reserved, value 0b00000000
3220     // 0:7   [8]  reserved: Reserved, value 0b00000000
3221     uint32_t packetFamily = 0;
3222     uint32_t packetId     = 37;    // Wrong packet id!!!
3223     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
3224
3225     // Create the Connection Acknowledged Packet
3226     arm::pipe::Packet connectionAcknowledgedPacket(header);
3227     // Write an invalid "Connection Acknowledged" packet into the mock profiling connection, to simulate an invalid
3228     // reply from an external profiling service
3229     mockProfilingConnection->WritePacket(std::move(connectionAcknowledgedPacket));
3230
3231     // Start the command thread
3232     profilingService.Update();
3233
3234     // Wait for the command thread to join
3235     options.m_EnableProfiling = false;
3236     profilingService.ResetExternalProfilingOptions(options, true);
3237
3238     streamRedirector.CancelRedirect();
3239
3240     // Check that the expected error has occurred and logged to the standard output
3241     if (ss.str().find("Functor with requested PacketId=37 and Version=4194304 does not exist") == std::string::npos)
3242     {
3243         std::cout << ss.str();
3244         BOOST_FAIL("Expected string not found.");
3245     }
3246 }
3247
3248 BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadRequestCounterDirectoryPacket)
3249 {
3250     // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
3251     LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
3252
3253     // Redirect the standard output to a local stream so that we can parse the warning message
3254     std::stringstream ss;
3255     StreamRedirector streamRedirector(std::cout, ss.rdbuf());
3256
3257     // Reset the profiling service to the uninitialized state
3258     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3259     options.m_EnableProfiling          = true;
3260     armnn::profiling::ProfilingService profilingService;
3261     profilingService.ResetExternalProfilingOptions(options, true);
3262
3263     // Swap the profiling connection factory in the profiling service instance with our mock one
3264     SwapProfilingConnectionFactoryHelper helper(profilingService);
3265
3266     // Bring the profiling service to the "Active" state
3267     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3268     helper.ForceTransitionToState(ProfilingState::NotConnected);
3269     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
3270     profilingService.Update();    // Create the profiling connection
3271     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
3272
3273     // Get the mock profiling connection
3274     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
3275     BOOST_CHECK(mockProfilingConnection);
3276
3277     // Write a valid "Request Counter Directory" packet into the mock profiling connection, to simulate a valid
3278     // reply from an external profiling service
3279
3280     // Request Counter Directory packet header (word 0, word 1 is always zero):
3281     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
3282     // 16:25 [10] packet_id: Packet identifier, value 0b0000000011
3283     // 8:15  [8]  reserved: Reserved, value 0b00000000
3284     // 0:7   [8]  reserved: Reserved, value 0b00000000
3285     uint32_t packetFamily = 0;
3286     uint32_t packetId     = 123;    // Wrong packet id!!!
3287     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
3288
3289     // Create the Request Counter Directory packet
3290     arm::pipe::Packet requestCounterDirectoryPacket(header);
3291
3292     // Write the packet to the mock profiling connection
3293     mockProfilingConnection->WritePacket(std::move(requestCounterDirectoryPacket));
3294
3295     // Start the command handler and the send thread
3296     profilingService.Update();
3297
3298     // Reset the profiling service to stop and join any running thread
3299     options.m_EnableProfiling = false;
3300     profilingService.ResetExternalProfilingOptions(options, true);
3301
3302     streamRedirector.CancelRedirect();
3303
3304     // Check that the expected error has occurred and logged to the standard output
3305     if (ss.str().find("Functor with requested PacketId=123 and Version=4194304 does not exist") == std::string::npos)
3306     {
3307         std::cout << ss.str();
3308         BOOST_FAIL("Expected string not found.");
3309     }
3310 }
3311
3312 BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacket)
3313 {
3314     // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
3315     LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
3316
3317     // Redirect the standard output to a local stream so that we can parse the warning message
3318     std::stringstream ss;
3319     StreamRedirector streamRedirector(std::cout, ss.rdbuf());
3320
3321     // Reset the profiling service to the uninitialized state
3322     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3323     options.m_EnableProfiling          = true;
3324     armnn::profiling::ProfilingService profilingService;
3325     profilingService.ResetExternalProfilingOptions(options, true);
3326
3327     // Swap the profiling connection factory in the profiling service instance with our mock one
3328     SwapProfilingConnectionFactoryHelper helper(profilingService);
3329
3330     // Bring the profiling service to the "Active" state
3331     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
3332     profilingService.Update();    // Initialize the counter directory
3333     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
3334     profilingService.Update();    // Create the profiling connection
3335     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
3336     profilingService.Update();    // Start the command handler and the send thread
3337
3338     // Get the mock profiling connection
3339     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
3340     BOOST_CHECK(mockProfilingConnection);
3341
3342     // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
3343     // external profiling service
3344
3345     // Periodic Counter Selection packet header:
3346     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
3347     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
3348     // 8:15  [8]  reserved: Reserved, value 0b00000000
3349     // 0:7   [8]  reserved: Reserved, value 0b00000000
3350     uint32_t packetFamily = 0;
3351     uint32_t packetId     = 999;    // Wrong packet id!!!
3352     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
3353
3354     // Create the Periodic Counter Selection packet
3355     // Length == 0, this will disable the collection of counters
3356     arm::pipe::Packet periodicCounterSelectionPacket(header);
3357
3358     // Write the packet to the mock profiling connection
3359     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
3360     profilingService.Update();
3361
3362     // Reset the profiling service to stop any running thread
3363     options.m_EnableProfiling = false;
3364     profilingService.ResetExternalProfilingOptions(options, true);
3365
3366     // Check that the expected error has occurred and logged to the standard output
3367     streamRedirector.CancelRedirect();
3368
3369     // Check that the expected error has occurred and logged to the standard output
3370     if (ss.str().find("Functor with requested PacketId=999 and Version=4194304 does not exist") == std::string::npos)
3371     {
3372         std::cout << ss.str();
3373         BOOST_FAIL("Expected string not found.");
3374     }
3375 }
3376
3377 BOOST_AUTO_TEST_CASE(CheckCounterIdMap)
3378 {
3379     CounterIdMap counterIdMap;
3380     BOOST_CHECK_THROW(counterIdMap.GetBackendId(0), armnn::Exception);
3381     BOOST_CHECK_THROW(counterIdMap.GetGlobalId(0, armnn::profiling::BACKEND_ID), armnn::Exception);
3382
3383     uint16_t globalCounterIds = 0;
3384
3385     armnn::BackendId cpuRefId(armnn::Compute::CpuRef);
3386     armnn::BackendId cpuAccId(armnn::Compute::CpuAcc);
3387
3388     std::vector<uint16_t> cpuRefCounters = {0, 1, 2, 3};
3389     std::vector<uint16_t> cpuAccCounters = {0, 1};
3390
3391     for (uint16_t backendCounterId : cpuRefCounters)
3392     {
3393         counterIdMap.RegisterMapping(globalCounterIds, backendCounterId, cpuRefId);
3394         ++globalCounterIds;
3395     }
3396     for (uint16_t backendCounterId : cpuAccCounters)
3397     {
3398         counterIdMap.RegisterMapping(globalCounterIds, backendCounterId, cpuAccId);
3399         ++globalCounterIds;
3400     }
3401
3402     BOOST_CHECK(counterIdMap.GetBackendId(0) == (std::pair<uint16_t, armnn::BackendId>(0, cpuRefId)));
3403     BOOST_CHECK(counterIdMap.GetBackendId(1) == (std::pair<uint16_t, armnn::BackendId>(1, cpuRefId)));
3404     BOOST_CHECK(counterIdMap.GetBackendId(2) == (std::pair<uint16_t, armnn::BackendId>(2, cpuRefId)));
3405     BOOST_CHECK(counterIdMap.GetBackendId(3) == (std::pair<uint16_t, armnn::BackendId>(3, cpuRefId)));
3406     BOOST_CHECK(counterIdMap.GetBackendId(4) == (std::pair<uint16_t, armnn::BackendId>(0, cpuAccId)));
3407     BOOST_CHECK(counterIdMap.GetBackendId(5) == (std::pair<uint16_t, armnn::BackendId>(1, cpuAccId)));
3408
3409     BOOST_CHECK(counterIdMap.GetGlobalId(0, cpuRefId) == 0);
3410     BOOST_CHECK(counterIdMap.GetGlobalId(1, cpuRefId) == 1);
3411     BOOST_CHECK(counterIdMap.GetGlobalId(2, cpuRefId) == 2);
3412     BOOST_CHECK(counterIdMap.GetGlobalId(3, cpuRefId) == 3);
3413     BOOST_CHECK(counterIdMap.GetGlobalId(0, cpuAccId) == 4);
3414     BOOST_CHECK(counterIdMap.GetGlobalId(1, cpuAccId) == 5);
3415 }
3416
3417 BOOST_AUTO_TEST_CASE(CheckRegisterBackendCounters)
3418 {
3419     uint16_t globalCounterIds = armnn::profiling::INFERENCES_RUN;
3420     armnn::BackendId cpuRefId(armnn::Compute::CpuRef);
3421
3422     // Reset the profiling service to the uninitialized state
3423     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3424     options.m_EnableProfiling          = true;
3425     ProfilingService profilingService;
3426     profilingService.ResetExternalProfilingOptions(options, true);
3427
3428     RegisterBackendCounters registerBackendCounters(globalCounterIds, cpuRefId, profilingService);
3429
3430
3431
3432     BOOST_CHECK(profilingService.GetCounterDirectory().GetCategories().empty());
3433     registerBackendCounters.RegisterCategory("categoryOne");
3434     auto categoryOnePtr = profilingService.GetCounterDirectory().GetCategory("categoryOne");
3435     BOOST_CHECK(categoryOnePtr);
3436
3437     BOOST_CHECK(profilingService.GetCounterDirectory().GetDevices().empty());
3438     globalCounterIds = registerBackendCounters.RegisterDevice("deviceOne");
3439     auto deviceOnePtr = profilingService.GetCounterDirectory().GetDevice(globalCounterIds);
3440     BOOST_CHECK(deviceOnePtr);
3441     BOOST_CHECK(deviceOnePtr->m_Name == "deviceOne");
3442
3443     BOOST_CHECK(profilingService.GetCounterDirectory().GetCounterSets().empty());
3444     globalCounterIds = registerBackendCounters.RegisterCounterSet("counterSetOne");
3445     auto counterSetOnePtr = profilingService.GetCounterDirectory().GetCounterSet(globalCounterIds);
3446     BOOST_CHECK(counterSetOnePtr);
3447     BOOST_CHECK(counterSetOnePtr->m_Name == "counterSetOne");
3448
3449     uint16_t newGlobalCounterId = registerBackendCounters.RegisterCounter(0,
3450                                                                           "categoryOne",
3451                                                                           0,
3452                                                                           0,
3453                                                                           1.f,
3454                                                                           "CounterOne",
3455                                                                           "first test counter");
3456     BOOST_CHECK(newGlobalCounterId = armnn::profiling::INFERENCES_RUN + 1);
3457     uint16_t mappedGlobalId = profilingService.GetCounterMappings().GetGlobalId(0, cpuRefId);
3458     BOOST_CHECK(mappedGlobalId == newGlobalCounterId);
3459     auto backendMapping = profilingService.GetCounterMappings().GetBackendId(newGlobalCounterId);
3460     BOOST_CHECK(backendMapping.first == 0);
3461     BOOST_CHECK(backendMapping.second == cpuRefId);
3462
3463     // Reset the profiling service to stop any running thread
3464     options.m_EnableProfiling = false;
3465     profilingService.ResetExternalProfilingOptions(options, true);
3466 }
3467
3468 BOOST_AUTO_TEST_CASE(CheckCounterStatusQuery)
3469 {
3470     armnn::IRuntime::CreationOptions options;
3471     options.m_ProfilingOptions.m_EnableProfiling = true;
3472
3473     // Reset the profiling service to the uninitialized state
3474     ProfilingService profilingService;
3475     profilingService.ResetExternalProfilingOptions(options.m_ProfilingOptions, true);
3476
3477     const armnn::BackendId cpuRefId(armnn::Compute::CpuRef);
3478     const armnn::BackendId cpuAccId(armnn::Compute::CpuAcc);
3479
3480     // Create BackendProfiling for each backend
3481     BackendProfiling backendProfilingCpuRef(options, profilingService, cpuRefId);
3482     BackendProfiling backendProfilingCpuAcc(options, profilingService, cpuAccId);
3483
3484     uint16_t initialNumGlobalCounterIds = armnn::profiling::INFERENCES_RUN;
3485
3486     // Create RegisterBackendCounters for CpuRef
3487     RegisterBackendCounters registerBackendCountersCpuRef(initialNumGlobalCounterIds, cpuRefId, profilingService);
3488
3489     // Create 'testCategory' in CounterDirectory (backend agnostic)
3490     BOOST_CHECK(profilingService.GetCounterDirectory().GetCategories().empty());
3491     registerBackendCountersCpuRef.RegisterCategory("testCategory");
3492     auto categoryOnePtr = profilingService.GetCounterDirectory().GetCategory("testCategory");
3493     BOOST_CHECK(categoryOnePtr);
3494
3495     // Counters:
3496     // Global | Local | Backend
3497     //    5   |   0   | CpuRef
3498     //    6   |   1   | CpuRef
3499     //    7   |   1   | CpuAcc
3500
3501     std::vector<uint16_t> cpuRefCounters = {0, 1};
3502     std::vector<uint16_t> cpuAccCounters = {0};
3503
3504     // Register the backend counters for CpuRef and validate GetGlobalId and GetBackendId
3505     uint16_t currentNumGlobalCounterIds = registerBackendCountersCpuRef.RegisterCounter(
3506             0, "testCategory", 0, 0, 1.f, "CpuRefCounter0", "Zeroth CpuRef Counter");
3507     BOOST_CHECK(currentNumGlobalCounterIds == initialNumGlobalCounterIds + 1);
3508     uint16_t mappedGlobalId = profilingService.GetCounterMappings().GetGlobalId(0, cpuRefId);
3509     BOOST_CHECK(mappedGlobalId == currentNumGlobalCounterIds);
3510     auto backendMapping = profilingService.GetCounterMappings().GetBackendId(currentNumGlobalCounterIds);
3511     BOOST_CHECK(backendMapping.first == 0);
3512     BOOST_CHECK(backendMapping.second == cpuRefId);
3513
3514     currentNumGlobalCounterIds = registerBackendCountersCpuRef.RegisterCounter(
3515             1, "testCategory", 0, 0, 1.f, "CpuRefCounter1", "First CpuRef Counter");
3516     BOOST_CHECK(currentNumGlobalCounterIds == initialNumGlobalCounterIds + 2);
3517     mappedGlobalId = profilingService.GetCounterMappings().GetGlobalId(1, cpuRefId);
3518     BOOST_CHECK(mappedGlobalId == currentNumGlobalCounterIds);
3519     backendMapping = profilingService.GetCounterMappings().GetBackendId(currentNumGlobalCounterIds);
3520     BOOST_CHECK(backendMapping.first == 1);
3521     BOOST_CHECK(backendMapping.second == cpuRefId);
3522
3523     // Create RegisterBackendCounters for CpuAcc
3524     RegisterBackendCounters registerBackendCountersCpuAcc(currentNumGlobalCounterIds, cpuAccId, profilingService);
3525
3526     // Register the backend counter for CpuAcc and validate GetGlobalId and GetBackendId
3527     currentNumGlobalCounterIds = registerBackendCountersCpuAcc.RegisterCounter(
3528             0, "testCategory", 0, 0, 1.f, "CpuAccCounter0", "Zeroth CpuAcc Counter");
3529     BOOST_CHECK(currentNumGlobalCounterIds == initialNumGlobalCounterIds + 3);
3530     mappedGlobalId = profilingService.GetCounterMappings().GetGlobalId(0, cpuAccId);
3531     BOOST_CHECK(mappedGlobalId == currentNumGlobalCounterIds);
3532     backendMapping = profilingService.GetCounterMappings().GetBackendId(currentNumGlobalCounterIds);
3533     BOOST_CHECK(backendMapping.first == 0);
3534     BOOST_CHECK(backendMapping.second == cpuAccId);
3535
3536     // Create vectors for active counters
3537     const std::vector<uint16_t> activeGlobalCounterIds = {5}; // CpuRef(0) activated
3538     const std::vector<uint16_t> newActiveGlobalCounterIds = {6, 7}; // CpuRef(0) and CpuAcc(1) activated
3539
3540     const uint32_t capturePeriod = 200;
3541     const uint32_t newCapturePeriod = 100;
3542
3543     // Set capture period and active counters in CaptureData
3544     profilingService.SetCaptureData(capturePeriod, activeGlobalCounterIds, {});
3545
3546     // Get vector of active counters for CpuRef and CpuAcc backends
3547     std::vector<CounterStatus> cpuRefCounterStatus = backendProfilingCpuRef.GetActiveCounters();
3548     std::vector<CounterStatus> cpuAccCounterStatus = backendProfilingCpuAcc.GetActiveCounters();
3549     BOOST_CHECK_EQUAL(cpuRefCounterStatus.size(), 1);
3550     BOOST_CHECK_EQUAL(cpuAccCounterStatus.size(), 0);
3551
3552     // Check active CpuRef counter
3553     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_GlobalCounterId, activeGlobalCounterIds[0]);
3554     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_BackendCounterId, cpuRefCounters[0]);
3555     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_SamplingRateInMicroseconds, capturePeriod);
3556     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_Enabled, true);
3557
3558     // Check inactive CpuRef counter
3559     CounterStatus inactiveCpuRefCounter = backendProfilingCpuRef.GetCounterStatus(cpuRefCounters[1]);
3560     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_GlobalCounterId, 6);
3561     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_BackendCounterId, cpuRefCounters[1]);
3562     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_SamplingRateInMicroseconds, 0);
3563     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_Enabled, false);
3564
3565     // Check inactive CpuAcc counter
3566     CounterStatus inactiveCpuAccCounter = backendProfilingCpuAcc.GetCounterStatus(cpuAccCounters[0]);
3567     BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_GlobalCounterId, 7);
3568     BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_BackendCounterId, cpuAccCounters[0]);
3569     BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_SamplingRateInMicroseconds, 0);
3570     BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_Enabled, false);
3571
3572     // Set new capture period and new active counters in CaptureData
3573     profilingService.SetCaptureData(newCapturePeriod, newActiveGlobalCounterIds, {});
3574
3575     // Get vector of active counters for CpuRef and CpuAcc backends
3576     cpuRefCounterStatus = backendProfilingCpuRef.GetActiveCounters();
3577     cpuAccCounterStatus = backendProfilingCpuAcc.GetActiveCounters();
3578     BOOST_CHECK_EQUAL(cpuRefCounterStatus.size(), 1);
3579     BOOST_CHECK_EQUAL(cpuAccCounterStatus.size(), 1);
3580
3581     // Check active CpuRef counter
3582     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_GlobalCounterId, newActiveGlobalCounterIds[0]);
3583     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_BackendCounterId, cpuRefCounters[1]);
3584     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_SamplingRateInMicroseconds, newCapturePeriod);
3585     BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_Enabled, true);
3586
3587     // Check active CpuAcc counter
3588     BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_GlobalCounterId, newActiveGlobalCounterIds[1]);
3589     BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_BackendCounterId, cpuAccCounters[0]);
3590     BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_SamplingRateInMicroseconds, newCapturePeriod);
3591     BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_Enabled, true);
3592
3593     // Check inactive CpuRef counter
3594     inactiveCpuRefCounter = backendProfilingCpuRef.GetCounterStatus(cpuRefCounters[0]);
3595     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_GlobalCounterId, 5);
3596     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_BackendCounterId, cpuRefCounters[0]);
3597     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_SamplingRateInMicroseconds, 0);
3598     BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_Enabled, false);
3599
3600     // Reset the profiling service to stop any running thread
3601     options.m_ProfilingOptions.m_EnableProfiling = false;
3602     profilingService.ResetExternalProfilingOptions(options.m_ProfilingOptions, true);
3603 }
3604
3605 BOOST_AUTO_TEST_CASE(CheckRegisterCounters)
3606 {
3607     armnn::Runtime::CreationOptions options;
3608     options.m_ProfilingOptions.m_EnableProfiling = true;
3609     MockBufferManager mockBuffer(1024);
3610
3611     CaptureData captureData;
3612     MockProfilingService mockProfilingService(mockBuffer, options.m_ProfilingOptions.m_EnableProfiling, captureData);
3613     armnn::BackendId cpuRefId(armnn::Compute::CpuRef);
3614
3615     mockProfilingService.RegisterMapping(6, 0, cpuRefId);
3616     mockProfilingService.RegisterMapping(7, 1, cpuRefId);
3617     mockProfilingService.RegisterMapping(8, 2, cpuRefId);
3618
3619     armnn::profiling::BackendProfiling backendProfiling(options,
3620                                                         mockProfilingService,
3621                                                         cpuRefId);
3622
3623     armnn::profiling::Timestamp timestamp;
3624     timestamp.timestamp = 1000998;
3625     timestamp.counterValues.emplace_back(0, 700);
3626     timestamp.counterValues.emplace_back(2, 93);
3627     std::vector<armnn::profiling::Timestamp> timestamps;
3628     timestamps.push_back(timestamp);
3629     backendProfiling.ReportCounters(timestamps);
3630
3631     auto readBuffer = mockBuffer.GetReadableBuffer();
3632
3633     uint32_t headerWord0 = ReadUint32(readBuffer, 0);
3634     uint32_t headerWord1 = ReadUint32(readBuffer, 4);
3635     uint64_t readTimestamp = ReadUint64(readBuffer, 8);
3636
3637     BOOST_TEST(((headerWord0 >> 26) & 0x0000003F) == 3); // packet family
3638     BOOST_TEST(((headerWord0 >> 19) & 0x0000007F) == 0); // packet class
3639     BOOST_TEST(((headerWord0 >> 16) & 0x00000007) == 0); // packet type
3640     BOOST_TEST(headerWord1 == 20);                       // data length
3641     BOOST_TEST(1000998 == readTimestamp);                // capture period
3642
3643     uint32_t offset = 16;
3644     // Check Counter Index
3645     uint16_t readIndex = ReadUint16(readBuffer, offset);
3646     BOOST_TEST(6 == readIndex);
3647
3648     // Check Counter Value
3649     offset += 2;
3650     uint32_t readValue = ReadUint32(readBuffer, offset);
3651     BOOST_TEST(700 == readValue);
3652
3653     // Check Counter Index
3654     offset += 4;
3655     readIndex = ReadUint16(readBuffer, offset);
3656     BOOST_TEST(8 == readIndex);
3657
3658     // Check Counter Value
3659     offset += 2;
3660     readValue = ReadUint32(readBuffer, offset);
3661     BOOST_TEST(93 == readValue);
3662 }
3663
3664 BOOST_AUTO_TEST_CASE(CheckFileFormat) {
3665     // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
3666     LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
3667
3668     // Create profiling options.
3669     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
3670     options.m_EnableProfiling = true;
3671     // Check the default value set to binary
3672     BOOST_CHECK(options.m_FileFormat == "binary");
3673
3674     // Change file format to an unsupported value
3675     options.m_FileFormat = "json";
3676     // Enable the profiling service
3677     armnn::profiling::ProfilingService profilingService;
3678     profilingService.ResetExternalProfilingOptions(options, true);
3679     // Start the command handler and the send thread
3680     profilingService.Update();
3681     BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::NotConnected);
3682
3683     // Redirect the output to a local stream so that we can parse the warning message
3684     std::stringstream ss;
3685     StreamRedirector streamRedirector(std::cout, ss.rdbuf());
3686
3687     // When Update is called and the current state is ProfilingState::NotConnected
3688     // an exception will be raised from GetProfilingConnection and displayed as warning in the output local stream
3689     profilingService.Update();
3690
3691     streamRedirector.CancelRedirect();
3692
3693     // Check that the expected error has occurred and logged to the standard output
3694     if (ss.str().find("Unsupported profiling file format, only binary is supported") == std::string::npos)
3695     {
3696         std::cout << ss.str();
3697         BOOST_FAIL("Expected string not found.");
3698     }
3699 }
3700
3701 BOOST_AUTO_TEST_SUITE_END()