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