IVGCVSW-4760 Change the offsets in the counter directory body_header to be from the...
[platform/upstream/armnn.git] / src / profiling / test / SendCounterPacketTests.cpp
1 //
2 // Copyright © 2019 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "ProfilingMocks.hpp"
7 #include "ProfilingTestUtils.hpp"
8 #include "SendCounterPacketTests.hpp"
9
10 #include <BufferManager.hpp>
11 #include <CounterDirectory.hpp>
12 #include <EncodeVersion.hpp>
13 #include <ProfilingUtils.hpp>
14 #include <SendCounterPacket.hpp>
15 #include <Processes.hpp>
16
17 #include <armnn/Exceptions.hpp>
18 #include <armnn/Conversion.hpp>
19 #include <armnn/Utils.hpp>
20
21 #include <boost/test/unit_test.hpp>
22 #include <boost/numeric/conversion/cast.hpp>
23
24 #include <chrono>
25
26 using namespace armnn::profiling;
27
28 namespace
29 {
30
31 // A short delay to wait for the thread to process a packet.
32 uint16_t constexpr WAIT_UNTIL_READABLE_MS = 20;
33
34 void SetNotConnectedProfilingState(ProfilingStateMachine& profilingStateMachine)
35 {
36     ProfilingState currentState = profilingStateMachine.GetCurrentState();
37     switch (currentState)
38     {
39     case ProfilingState::WaitingForAck:
40         profilingStateMachine.TransitionToState(ProfilingState::Active);
41         ARMNN_FALLTHROUGH;
42     case ProfilingState::Uninitialised:
43         ARMNN_FALLTHROUGH;
44     case ProfilingState::Active:
45         profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
46         ARMNN_FALLTHROUGH;
47     case ProfilingState::NotConnected:
48         return;
49     default:
50         BOOST_CHECK_MESSAGE(false, "Invalid profiling state");
51     }
52 }
53
54 void SetWaitingForAckProfilingState(ProfilingStateMachine& profilingStateMachine)
55 {
56     ProfilingState currentState = profilingStateMachine.GetCurrentState();
57     switch (currentState)
58     {
59     case ProfilingState::Uninitialised:
60         ARMNN_FALLTHROUGH;
61     case ProfilingState::Active:
62         profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
63         ARMNN_FALLTHROUGH;
64     case ProfilingState::NotConnected:
65         profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
66         ARMNN_FALLTHROUGH;
67     case ProfilingState::WaitingForAck:
68         return;
69     default:
70         BOOST_CHECK_MESSAGE(false, "Invalid profiling state");
71     }
72 }
73
74 void SetActiveProfilingState(ProfilingStateMachine& profilingStateMachine)
75 {
76     ProfilingState currentState = profilingStateMachine.GetCurrentState();
77     switch (currentState)
78     {
79     case ProfilingState::Uninitialised:
80         profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
81         ARMNN_FALLTHROUGH;
82     case ProfilingState::NotConnected:
83         profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
84         ARMNN_FALLTHROUGH;
85     case ProfilingState::WaitingForAck:
86         profilingStateMachine.TransitionToState(ProfilingState::Active);
87         ARMNN_FALLTHROUGH;
88     case ProfilingState::Active:
89         return;
90     default:
91         BOOST_CHECK_MESSAGE(false, "Invalid profiling state");
92     }
93 }
94
95 } // Anonymous namespace
96
97 BOOST_AUTO_TEST_SUITE(SendCounterPacketTests)
98
99 using PacketType = MockProfilingConnection::PacketType;
100
101 BOOST_AUTO_TEST_CASE(MockSendCounterPacketTest)
102 {
103     MockBufferManager mockBuffer(512);
104     MockSendCounterPacket mockSendCounterPacket(mockBuffer);
105
106     mockSendCounterPacket.SendStreamMetaDataPacket();
107
108     auto packetBuffer = mockBuffer.GetReadableBuffer();
109     const char* buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
110
111     BOOST_TEST(strcmp(buffer, "SendStreamMetaDataPacket") == 0);
112
113     mockBuffer.MarkRead(packetBuffer);
114
115     CounterDirectory counterDirectory;
116     mockSendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
117
118     packetBuffer = mockBuffer.GetReadableBuffer();
119     buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
120
121     BOOST_TEST(strcmp(buffer, "SendCounterDirectoryPacket") == 0);
122
123     mockBuffer.MarkRead(packetBuffer);
124
125     uint64_t timestamp = 0;
126     std::vector<CounterValue> indexValuePairs;
127
128     mockSendCounterPacket.SendPeriodicCounterCapturePacket(timestamp, indexValuePairs);
129
130     packetBuffer = mockBuffer.GetReadableBuffer();
131     buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
132
133     BOOST_TEST(strcmp(buffer, "SendPeriodicCounterCapturePacket") == 0);
134
135     mockBuffer.MarkRead(packetBuffer);
136
137     uint32_t capturePeriod = 0;
138     std::vector<uint16_t> selectedCounterIds;
139     mockSendCounterPacket.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
140
141     packetBuffer = mockBuffer.GetReadableBuffer();
142     buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
143
144     BOOST_TEST(strcmp(buffer, "SendPeriodicCounterSelectionPacket") == 0);
145
146     mockBuffer.MarkRead(packetBuffer);
147 }
148
149 BOOST_AUTO_TEST_CASE(SendPeriodicCounterSelectionPacketTest)
150 {
151     // Error no space left in buffer
152     MockBufferManager mockBuffer1(10);
153     SendCounterPacket sendPacket1(mockBuffer1);
154
155     uint32_t capturePeriod = 1000;
156     std::vector<uint16_t> selectedCounterIds;
157     BOOST_CHECK_THROW(sendPacket1.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds),
158                       BufferExhaustion);
159
160     // Packet without any counters
161     MockBufferManager mockBuffer2(512);
162     SendCounterPacket sendPacket2(mockBuffer2);
163
164     sendPacket2.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
165     auto readBuffer2 = mockBuffer2.GetReadableBuffer();
166
167     uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
168     uint32_t headerWord1 = ReadUint32(readBuffer2, 4);
169     uint32_t period = ReadUint32(readBuffer2, 8);
170
171     BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0);  // packet family
172     BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 4); // packet id
173     BOOST_TEST(headerWord1 == 4);                   // data lenght
174     BOOST_TEST(period == 1000);                     // capture period
175
176     // Full packet message
177     MockBufferManager mockBuffer3(512);
178     SendCounterPacket sendPacket3(mockBuffer3);
179
180     selectedCounterIds.reserve(5);
181     selectedCounterIds.emplace_back(100);
182     selectedCounterIds.emplace_back(200);
183     selectedCounterIds.emplace_back(300);
184     selectedCounterIds.emplace_back(400);
185     selectedCounterIds.emplace_back(500);
186     sendPacket3.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
187     auto readBuffer3 = mockBuffer3.GetReadableBuffer();
188
189     headerWord0 = ReadUint32(readBuffer3, 0);
190     headerWord1 = ReadUint32(readBuffer3, 4);
191     period = ReadUint32(readBuffer3, 8);
192
193     BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0);  // packet family
194     BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 4); // packet id
195     BOOST_TEST(headerWord1 == 14);                  // data lenght
196     BOOST_TEST(period == 1000);                     // capture period
197
198     uint16_t counterId = 0;
199     uint32_t offset = 12;
200
201     // Counter Ids
202     for(const uint16_t& id : selectedCounterIds)
203     {
204         counterId = ReadUint16(readBuffer3, offset);
205         BOOST_TEST(counterId == id);
206         offset += 2;
207     }
208 }
209
210 BOOST_AUTO_TEST_CASE(SendPeriodicCounterCapturePacketTest)
211 {
212     ProfilingStateMachine profilingStateMachine;
213
214     // Error no space left in buffer
215     MockBufferManager mockBuffer1(10);
216     SendCounterPacket sendPacket1(mockBuffer1);
217
218     auto captureTimestamp = std::chrono::steady_clock::now();
219     uint64_t time =  static_cast<uint64_t >(captureTimestamp.time_since_epoch().count());
220     std::vector<CounterValue> indexValuePairs;
221
222     BOOST_CHECK_THROW(sendPacket1.SendPeriodicCounterCapturePacket(time, indexValuePairs),
223                       BufferExhaustion);
224
225     // Packet without any counters
226     MockBufferManager mockBuffer2(512);
227     SendCounterPacket sendPacket2(mockBuffer2);
228
229     sendPacket2.SendPeriodicCounterCapturePacket(time, indexValuePairs);
230     auto readBuffer2 = mockBuffer2.GetReadableBuffer();
231
232     uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
233     uint32_t headerWord1 = ReadUint32(readBuffer2, 4);
234     uint64_t readTimestamp = ReadUint64(readBuffer2, 8);
235
236     BOOST_TEST(((headerWord0 >> 26) & 0x0000003F) == 3); // packet family
237     BOOST_TEST(((headerWord0 >> 19) & 0x0000007F) == 0); // packet class
238     BOOST_TEST(((headerWord0 >> 16) & 0x00000007) == 0); // packet type
239     BOOST_TEST(headerWord1 == 8);                        // data length
240     BOOST_TEST(time == readTimestamp);                   // capture period
241
242     // Full packet message
243     MockBufferManager mockBuffer3(512);
244     SendCounterPacket sendPacket3(mockBuffer3);
245
246     indexValuePairs.reserve(5);
247     indexValuePairs.emplace_back(CounterValue{0, 100});
248     indexValuePairs.emplace_back(CounterValue{1, 200});
249     indexValuePairs.emplace_back(CounterValue{2, 300});
250     indexValuePairs.emplace_back(CounterValue{3, 400});
251     indexValuePairs.emplace_back(CounterValue{4, 500});
252     sendPacket3.SendPeriodicCounterCapturePacket(time, indexValuePairs);
253     auto readBuffer3 = mockBuffer3.GetReadableBuffer();
254
255     headerWord0 = ReadUint32(readBuffer3, 0);
256     headerWord1 = ReadUint32(readBuffer3, 4);
257     uint64_t readTimestamp2 = ReadUint64(readBuffer3, 8);
258
259     BOOST_TEST(((headerWord0 >> 26) & 0x0000003F) == 3); // packet family
260     BOOST_TEST(((headerWord0 >> 19) & 0x0000007F) == 0); // packet class
261     BOOST_TEST(((headerWord0 >> 16) & 0x00000007) == 0); // packet type
262     BOOST_TEST(headerWord1 == 38);                       // data length
263     BOOST_TEST(time == readTimestamp2);                  // capture period
264
265     uint16_t counterIndex = 0;
266     uint32_t counterValue = 100;
267     uint32_t offset = 16;
268
269     // Counter Ids
270     for (auto it = indexValuePairs.begin(), end = indexValuePairs.end(); it != end; ++it)
271     {
272         // Check Counter Index
273         uint16_t readIndex = ReadUint16(readBuffer3, offset);
274         BOOST_TEST(counterIndex == readIndex);
275         counterIndex++;
276         offset += 2;
277
278         // Check Counter Value
279         uint32_t readValue = ReadUint32(readBuffer3, offset);
280         BOOST_TEST(counterValue == readValue);
281         counterValue += 100;
282         offset += 4;
283     }
284
285 }
286
287 BOOST_AUTO_TEST_CASE(SendStreamMetaDataPacketTest)
288 {
289     using boost::numeric_cast;
290
291     uint32_t sizeUint32 = numeric_cast<uint32_t>(sizeof(uint32_t));
292
293     // Error no space left in buffer
294     MockBufferManager mockBuffer1(10);
295     SendCounterPacket sendPacket1(mockBuffer1);
296     BOOST_CHECK_THROW(sendPacket1.SendStreamMetaDataPacket(), armnn::profiling::BufferExhaustion);
297
298     // Full metadata packet
299
300     std::string processName = GetProcessName().substr(0, 60);
301
302     uint32_t infoSize =            numeric_cast<uint32_t>(GetSoftwareInfo().size()) + 1;
303     uint32_t hardwareVersionSize = numeric_cast<uint32_t>(GetHardwareVersion().size()) + 1;
304     uint32_t softwareVersionSize = numeric_cast<uint32_t>(GetSoftwareVersion().size()) + 1;
305     uint32_t processNameSize =     numeric_cast<uint32_t>(processName.size()) + 1;
306
307     uint32_t packetEntries = 6;
308
309     MockBufferManager mockBuffer2(512);
310     SendCounterPacket sendPacket2(mockBuffer2);
311     sendPacket2.SendStreamMetaDataPacket();
312     auto readBuffer2 = mockBuffer2.GetReadableBuffer();
313
314     uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
315     uint32_t headerWord1 = ReadUint32(readBuffer2, sizeUint32);
316
317     BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0); // packet family
318     BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 0); // packet id
319
320     uint32_t totalLength = numeric_cast<uint32_t>(2 * sizeUint32 + 10 * sizeUint32 + infoSize + hardwareVersionSize +
321                                                   softwareVersionSize + processNameSize + sizeUint32 +
322                                                   2 * packetEntries * sizeUint32);
323
324     BOOST_TEST(headerWord1 == totalLength - (2 * sizeUint32)); // data length
325
326     uint32_t offset = sizeUint32 * 2;
327     BOOST_TEST(ReadUint32(readBuffer2, offset) == SendCounterPacket::PIPE_MAGIC); // pipe_magic
328     offset += sizeUint32;
329     BOOST_TEST(ReadUint32(readBuffer2, offset) == EncodeVersion(1, 0, 0)); // stream_metadata_version
330     offset += sizeUint32;
331     BOOST_TEST(ReadUint32(readBuffer2, offset) == MAX_METADATA_PACKET_LENGTH); // max_data_len
332     offset += sizeUint32;
333     int pid = armnnUtils::Processes::GetCurrentId();
334     BOOST_TEST(ReadUint32(readBuffer2, offset) == numeric_cast<uint32_t>(pid));
335     offset += sizeUint32;
336     uint32_t poolOffset = 10 * sizeUint32;
337     BOOST_TEST(ReadUint32(readBuffer2, offset) == poolOffset); // offset_info
338     offset += sizeUint32;
339     poolOffset += infoSize;
340     BOOST_TEST(ReadUint32(readBuffer2, offset) == poolOffset); // offset_hw_version
341     offset += sizeUint32;
342     poolOffset += hardwareVersionSize;
343     BOOST_TEST(ReadUint32(readBuffer2, offset) == poolOffset); // offset_sw_version
344     offset += sizeUint32;
345     poolOffset += softwareVersionSize;
346     BOOST_TEST(ReadUint32(readBuffer2, offset) == poolOffset); // offset_process_name
347     offset += sizeUint32;
348     poolOffset += processNameSize;
349     BOOST_TEST(ReadUint32(readBuffer2, offset) == poolOffset); // offset_packet_version_table
350     offset += sizeUint32;
351     BOOST_TEST(ReadUint32(readBuffer2, offset) == 0); // reserved
352
353     const unsigned char* readData2 = readBuffer2->GetReadableData();
354
355     offset += sizeUint32;
356     if (infoSize)
357     {
358         BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetSoftwareInfo().c_str()) == 0);
359         offset += infoSize;
360     }
361
362     if (hardwareVersionSize)
363     {
364         BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetHardwareVersion().c_str()) == 0);
365         offset += hardwareVersionSize;
366     }
367
368     if (softwareVersionSize)
369     {
370         BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetSoftwareVersion().c_str()) == 0);
371         offset += softwareVersionSize;
372     }
373
374     if (processNameSize)
375     {
376         BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetProcessName().c_str()) == 0);
377         offset += processNameSize;
378     }
379
380     if (packetEntries)
381     {
382         BOOST_TEST((ReadUint32(readBuffer2, offset) >> 16) == packetEntries);
383         offset += sizeUint32;
384         for (uint32_t i = 0; i < packetEntries - 1; ++i)
385         {
386             BOOST_TEST(((ReadUint32(readBuffer2, offset) >> 26) & 0x3F) == 0);
387             BOOST_TEST(((ReadUint32(readBuffer2, offset) >> 16) & 0x3FF) == i);
388             offset += sizeUint32;
389             BOOST_TEST(ReadUint32(readBuffer2, offset) == EncodeVersion(1, 0, 0));
390             offset += sizeUint32;
391         }
392
393         BOOST_TEST(((ReadUint32(readBuffer2, offset) >> 26) & 0x3F) == 1);
394         BOOST_TEST(((ReadUint32(readBuffer2, offset) >> 16) & 0x3FF) == 0);
395         offset += sizeUint32;
396         BOOST_TEST(ReadUint32(readBuffer2, offset) == EncodeVersion(1, 0, 0));
397         offset += sizeUint32;
398     }
399
400     BOOST_TEST(offset == totalLength);
401 }
402
403 BOOST_AUTO_TEST_CASE(CreateDeviceRecordTest)
404 {
405     MockBufferManager mockBuffer(0);
406     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
407
408     // Create a device for testing
409     uint16_t deviceUid = 27;
410     const std::string deviceName = "some_device";
411     uint16_t deviceCores = 3;
412     const DevicePtr device = std::make_unique<Device>(deviceUid, deviceName, deviceCores);
413
414     // Create a device record
415     SendCounterPacket::DeviceRecord deviceRecord;
416     std::string errorMessage;
417     bool result = sendCounterPacketTest.CreateDeviceRecordTest(device, deviceRecord, errorMessage);
418
419     BOOST_CHECK(result);
420     BOOST_CHECK(errorMessage.empty());
421     BOOST_CHECK(deviceRecord.size() == 6); // Size in words: header [2] + device name [4]
422
423     uint16_t deviceRecordWord0[]
424     {
425         static_cast<uint16_t>(deviceRecord[0] >> 16),
426         static_cast<uint16_t>(deviceRecord[0])
427     };
428     BOOST_CHECK(deviceRecordWord0[0] == deviceUid); // uid
429     BOOST_CHECK(deviceRecordWord0[1] == deviceCores); // cores
430     BOOST_CHECK(deviceRecord[1] == 0); // name_offset
431     BOOST_CHECK(deviceRecord[2] == deviceName.size() + 1); // The length of the SWTrace string (name)
432     BOOST_CHECK(std::memcmp(deviceRecord.data() + 3, deviceName.data(), deviceName.size()) == 0); // name
433 }
434
435 BOOST_AUTO_TEST_CASE(CreateInvalidDeviceRecordTest)
436 {
437     MockBufferManager mockBuffer(0);
438     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
439
440     // Create a device for testing
441     uint16_t deviceUid = 27;
442     const std::string deviceName = "some€£invalid‡device";
443     uint16_t deviceCores = 3;
444     const DevicePtr device = std::make_unique<Device>(deviceUid, deviceName, deviceCores);
445
446     // Create a device record
447     SendCounterPacket::DeviceRecord deviceRecord;
448     std::string errorMessage;
449     bool result = sendCounterPacketTest.CreateDeviceRecordTest(device, deviceRecord, errorMessage);
450
451     BOOST_CHECK(!result);
452     BOOST_CHECK(!errorMessage.empty());
453     BOOST_CHECK(deviceRecord.empty());
454 }
455
456 BOOST_AUTO_TEST_CASE(CreateCounterSetRecordTest)
457 {
458     MockBufferManager mockBuffer(0);
459     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
460
461     // Create a counter set for testing
462     uint16_t counterSetUid = 27;
463     const std::string counterSetName = "some_counter_set";
464     uint16_t counterSetCount = 3421;
465     const CounterSetPtr counterSet = std::make_unique<CounterSet>(counterSetUid, counterSetName, counterSetCount);
466
467     // Create a counter set record
468     SendCounterPacket::CounterSetRecord counterSetRecord;
469     std::string errorMessage;
470     bool result = sendCounterPacketTest.CreateCounterSetRecordTest(counterSet, counterSetRecord, errorMessage);
471
472     BOOST_CHECK(result);
473     BOOST_CHECK(errorMessage.empty());
474     BOOST_CHECK(counterSetRecord.size() == 8); // Size in words: header [2] + counter set name [6]
475
476     uint16_t counterSetRecordWord0[]
477     {
478         static_cast<uint16_t>(counterSetRecord[0] >> 16),
479         static_cast<uint16_t>(counterSetRecord[0])
480     };
481     BOOST_CHECK(counterSetRecordWord0[0] == counterSetUid); // uid
482     BOOST_CHECK(counterSetRecordWord0[1] == counterSetCount); // cores
483     BOOST_CHECK(counterSetRecord[1] == 0); // name_offset
484     BOOST_CHECK(counterSetRecord[2] == counterSetName.size() + 1); // The length of the SWTrace string (name)
485     BOOST_CHECK(std::memcmp(counterSetRecord.data() + 3, counterSetName.data(), counterSetName.size()) == 0); // name
486 }
487
488 BOOST_AUTO_TEST_CASE(CreateInvalidCounterSetRecordTest)
489 {
490     MockBufferManager mockBuffer(0);
491     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
492
493     // Create a counter set for testing
494     uint16_t counterSetUid = 27;
495     const std::string counterSetName = "some invalid_counter€£set";
496     uint16_t counterSetCount = 3421;
497     const CounterSetPtr counterSet = std::make_unique<CounterSet>(counterSetUid, counterSetName, counterSetCount);
498
499     // Create a counter set record
500     SendCounterPacket::CounterSetRecord counterSetRecord;
501     std::string errorMessage;
502     bool result = sendCounterPacketTest.CreateCounterSetRecordTest(counterSet, counterSetRecord, errorMessage);
503
504     BOOST_CHECK(!result);
505     BOOST_CHECK(!errorMessage.empty());
506     BOOST_CHECK(counterSetRecord.empty());
507 }
508
509 BOOST_AUTO_TEST_CASE(CreateEventRecordTest)
510 {
511     MockBufferManager mockBuffer(0);
512     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
513
514     // Create a counter for testing
515     uint16_t counterUid = 7256;
516     uint16_t maxCounterUid = 132;
517     uint16_t deviceUid = 132;
518     uint16_t counterSetUid = 4497;
519     uint16_t counterClass = 1;
520     uint16_t counterInterpolation = 1;
521     double counterMultiplier = 1234.567f;
522     const std::string counterName = "some_valid_counter";
523     const std::string counterDescription = "a_counter_for_testing";
524     const std::string counterUnits = "Mrads2";
525     const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
526                                                          counterUid,
527                                                          maxCounterUid,
528                                                          counterClass,
529                                                          counterInterpolation,
530                                                          counterMultiplier,
531                                                          counterName,
532                                                          counterDescription,
533                                                          counterUnits,
534                                                          deviceUid,
535                                                          counterSetUid);
536     ARMNN_ASSERT(counter);
537
538     // Create an event record
539     SendCounterPacket::EventRecord eventRecord;
540     std::string errorMessage;
541     bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
542
543     BOOST_CHECK(result);
544     BOOST_CHECK(errorMessage.empty());
545     BOOST_CHECK(eventRecord.size() == 24); // Size in words: header [8] + counter name [6] + description [7] + units [3]
546
547     uint16_t eventRecordWord0[]
548     {
549         static_cast<uint16_t>(eventRecord[0] >> 16),
550         static_cast<uint16_t>(eventRecord[0])
551     };
552     uint16_t eventRecordWord1[]
553     {
554         static_cast<uint16_t>(eventRecord[1] >> 16),
555         static_cast<uint16_t>(eventRecord[1])
556     };
557     uint16_t eventRecordWord2[]
558     {
559         static_cast<uint16_t>(eventRecord[2] >> 16),
560         static_cast<uint16_t>(eventRecord[2])
561     };
562     uint32_t eventRecordWord34[]
563     {
564         eventRecord[3],
565         eventRecord[4]
566     };
567     BOOST_CHECK(eventRecordWord0[0] == maxCounterUid); // max_counter_uid
568     BOOST_CHECK(eventRecordWord0[1] == counterUid); // counter_uid
569     BOOST_CHECK(eventRecordWord1[0] == deviceUid); // device
570     BOOST_CHECK(eventRecordWord1[1] == counterSetUid); // counter_set
571     BOOST_CHECK(eventRecordWord2[0] == counterClass); // class
572     BOOST_CHECK(eventRecordWord2[1] == counterInterpolation); // interpolation
573     BOOST_CHECK(std::memcmp(eventRecordWord34, &counterMultiplier, sizeof(counterMultiplier)) == 0); // multiplier
574
575     ARMNN_NO_CONVERSION_WARN_BEGIN
576     uint32_t counterNameOffset = 0; // The name is the first item in pool
577     uint32_t counterDescriptionOffset = counterNameOffset + // Counter name offset
578                                         4u + // Counter name length (uint32_t)
579                                         counterName.size() + // 18u
580                                         1u + // Null-terminator
581                                         1u; // Rounding to the next word
582     size_t counterUnitsOffset = counterDescriptionOffset + // Counter description offset
583                                 4u + // Counter description length (uint32_t)
584                                 counterDescription.size() + // 21u
585                                 1u + // Null-terminator
586                                 2u; // Rounding to the next word
587     ARMNN_NO_CONVERSION_WARN_END
588
589     BOOST_CHECK(eventRecord[5] == counterNameOffset); // name_offset
590     BOOST_CHECK(eventRecord[6] == counterDescriptionOffset); // description_offset
591     BOOST_CHECK(eventRecord[7] == counterUnitsOffset); // units_offset
592
593     auto eventRecordPool = reinterpret_cast<unsigned char*>(eventRecord.data() + 8u); // The start of the pool
594     size_t uint32_t_size = sizeof(uint32_t);
595
596     // The length of the SWTrace string (name)
597     BOOST_CHECK(eventRecordPool[counterNameOffset] == counterName.size() + 1);
598     // The counter name
599     BOOST_CHECK(std::memcmp(eventRecordPool +
600                             counterNameOffset + // Offset
601                             uint32_t_size /* The length of the name */,
602                             counterName.data(),
603                             counterName.size()) == 0); // name
604     // The null-terminator at the end of the name
605     BOOST_CHECK(eventRecordPool[counterNameOffset + uint32_t_size + counterName.size()] == '\0');
606
607     // The length of the SWTrace string (description)
608     BOOST_CHECK(eventRecordPool[counterDescriptionOffset] == counterDescription.size() + 1);
609     // The counter description
610     BOOST_CHECK(std::memcmp(eventRecordPool +
611                             counterDescriptionOffset + // Offset
612                             uint32_t_size /* The length of the description */,
613                             counterDescription.data(),
614                             counterDescription.size()) == 0); // description
615     // The null-terminator at the end of the description
616     BOOST_CHECK(eventRecordPool[counterDescriptionOffset + uint32_t_size + counterDescription.size()] == '\0');
617
618     // The length of the SWTrace namestring (units)
619     BOOST_CHECK(eventRecordPool[counterUnitsOffset] == counterUnits.size() + 1);
620     // The counter units
621     BOOST_CHECK(std::memcmp(eventRecordPool +
622                             counterUnitsOffset + // Offset
623                             uint32_t_size /* The length of the units */,
624                             counterUnits.data(),
625                             counterUnits.size()) == 0); // units
626     // The null-terminator at the end of the units
627     BOOST_CHECK(eventRecordPool[counterUnitsOffset + uint32_t_size + counterUnits.size()] == '\0');
628 }
629
630 BOOST_AUTO_TEST_CASE(CreateEventRecordNoUnitsTest)
631 {
632     MockBufferManager mockBuffer(0);
633     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
634
635     // Create a counter for testing
636     uint16_t counterUid = 44312;
637     uint16_t maxCounterUid = 345;
638     uint16_t deviceUid = 101;
639     uint16_t counterSetUid = 34035;
640     uint16_t counterClass = 0;
641     uint16_t counterInterpolation = 1;
642     double counterMultiplier = 4435.0023f;
643     const std::string counterName = "some_valid_counter";
644     const std::string counterDescription = "a_counter_for_testing";
645     const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
646                                                          counterUid,
647                                                          maxCounterUid,
648                                                          counterClass,
649                                                          counterInterpolation,
650                                                          counterMultiplier,
651                                                          counterName,
652                                                          counterDescription,
653                                                          "",
654                                                          deviceUid,
655                                                          counterSetUid);
656     ARMNN_ASSERT(counter);
657
658     // Create an event record
659     SendCounterPacket::EventRecord eventRecord;
660     std::string errorMessage;
661     bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
662
663     BOOST_CHECK(result);
664     BOOST_CHECK(errorMessage.empty());
665     BOOST_CHECK(eventRecord.size() == 21); // Size in words: header [8] + counter name [6] + description [7]
666
667     uint16_t eventRecordWord0[]
668     {
669         static_cast<uint16_t>(eventRecord[0] >> 16),
670         static_cast<uint16_t>(eventRecord[0])
671     };
672     uint16_t eventRecordWord1[]
673     {
674         static_cast<uint16_t>(eventRecord[1] >> 16),
675         static_cast<uint16_t>(eventRecord[1])
676     };
677     uint16_t eventRecordWord2[]
678     {
679         static_cast<uint16_t>(eventRecord[2] >> 16),
680         static_cast<uint16_t>(eventRecord[2])
681     };
682     uint32_t eventRecordWord34[]
683     {
684         eventRecord[3],
685         eventRecord[4]
686     };
687     BOOST_CHECK(eventRecordWord0[0] == maxCounterUid); // max_counter_uid
688     BOOST_CHECK(eventRecordWord0[1] == counterUid); // counter_uid
689     BOOST_CHECK(eventRecordWord1[0] == deviceUid); // device
690     BOOST_CHECK(eventRecordWord1[1] == counterSetUid); // counter_set
691     BOOST_CHECK(eventRecordWord2[0] == counterClass); // class
692     BOOST_CHECK(eventRecordWord2[1] == counterInterpolation); // interpolation
693     BOOST_CHECK(std::memcmp(eventRecordWord34, &counterMultiplier, sizeof(counterMultiplier)) == 0); // multiplier
694
695     ARMNN_NO_CONVERSION_WARN_BEGIN
696     uint32_t counterNameOffset = 0; // The name is the first item in pool
697     uint32_t counterDescriptionOffset = counterNameOffset + // Counter name offset
698                                         4u + // Counter name length (uint32_t)
699                                         counterName.size() + // 18u
700                                         1u + // Null-terminator
701                                         1u; // Rounding to the next word
702     ARMNN_NO_CONVERSION_WARN_END
703
704     BOOST_CHECK(eventRecord[5] == counterNameOffset); // name_offset
705     BOOST_CHECK(eventRecord[6] == counterDescriptionOffset); // description_offset
706     BOOST_CHECK(eventRecord[7] == 0); // units_offset
707
708     auto eventRecordPool = reinterpret_cast<unsigned char*>(eventRecord.data() + 8u); // The start of the pool
709     size_t uint32_t_size = sizeof(uint32_t);
710
711     // The length of the SWTrace string (name)
712     BOOST_CHECK(eventRecordPool[counterNameOffset] == counterName.size() + 1);
713     // The counter name
714     BOOST_CHECK(std::memcmp(eventRecordPool +
715                             counterNameOffset + // Offset
716                             uint32_t_size, // The length of the name
717                             counterName.data(),
718                             counterName.size()) == 0); // name
719     // The null-terminator at the end of the name
720     BOOST_CHECK(eventRecordPool[counterNameOffset + uint32_t_size + counterName.size()] == '\0');
721
722     // The length of the SWTrace string (description)
723     BOOST_CHECK(eventRecordPool[counterDescriptionOffset] == counterDescription.size() + 1);
724     // The counter description
725     BOOST_CHECK(std::memcmp(eventRecordPool +
726                             counterDescriptionOffset + // Offset
727                             uint32_t_size, // The length of the description
728                             counterDescription.data(),
729                             counterDescription.size()) == 0); // description
730     // The null-terminator at the end of the description
731     BOOST_CHECK(eventRecordPool[counterDescriptionOffset + uint32_t_size + counterDescription.size()] == '\0');
732 }
733
734 BOOST_AUTO_TEST_CASE(CreateInvalidEventRecordTest1)
735 {
736     MockBufferManager mockBuffer(0);
737     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
738
739     // Create a counter for testing
740     uint16_t counterUid = 7256;
741     uint16_t maxCounterUid = 132;
742     uint16_t deviceUid = 132;
743     uint16_t counterSetUid = 4497;
744     uint16_t counterClass = 1;
745     uint16_t counterInterpolation = 1;
746     double counterMultiplier = 1234.567f;
747     const std::string counterName = "some_invalid_counter £££"; // Invalid name
748     const std::string counterDescription = "a_counter_for_testing";
749     const std::string counterUnits = "Mrads2";
750     const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
751                                                          counterUid,
752                                                          maxCounterUid,
753                                                          counterClass,
754                                                          counterInterpolation,
755                                                          counterMultiplier,
756                                                          counterName,
757                                                          counterDescription,
758                                                          counterUnits,
759                                                          deviceUid,
760                                                          counterSetUid);
761     ARMNN_ASSERT(counter);
762
763     // Create an event record
764     SendCounterPacket::EventRecord eventRecord;
765     std::string errorMessage;
766     bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
767
768     BOOST_CHECK(!result);
769     BOOST_CHECK(!errorMessage.empty());
770     BOOST_CHECK(eventRecord.empty());
771 }
772
773 BOOST_AUTO_TEST_CASE(CreateInvalidEventRecordTest2)
774 {
775     MockBufferManager mockBuffer(0);
776     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
777
778     // Create a counter for testing
779     uint16_t counterUid = 7256;
780     uint16_t maxCounterUid = 132;
781     uint16_t deviceUid = 132;
782     uint16_t counterSetUid = 4497;
783     uint16_t counterClass = 1;
784     uint16_t counterInterpolation = 1;
785     double counterMultiplier = 1234.567f;
786     const std::string counterName = "some_invalid_counter";
787     const std::string counterDescription = "an invalid d€scription"; // Invalid description
788     const std::string counterUnits = "Mrads2";
789     const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
790                                                          counterUid,
791                                                          maxCounterUid,
792                                                          counterClass,
793                                                          counterInterpolation,
794                                                          counterMultiplier,
795                                                          counterName,
796                                                          counterDescription,
797                                                          counterUnits,
798                                                          deviceUid,
799                                                          counterSetUid);
800     ARMNN_ASSERT(counter);
801
802     // Create an event record
803     SendCounterPacket::EventRecord eventRecord;
804     std::string errorMessage;
805     bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
806
807     BOOST_CHECK(!result);
808     BOOST_CHECK(!errorMessage.empty());
809     BOOST_CHECK(eventRecord.empty());
810 }
811
812 BOOST_AUTO_TEST_CASE(CreateInvalidEventRecordTest3)
813 {
814     MockBufferManager mockBuffer(0);
815     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
816
817     // Create a counter for testing
818     uint16_t counterUid = 7256;
819     uint16_t maxCounterUid = 132;
820     uint16_t deviceUid = 132;
821     uint16_t counterSetUid = 4497;
822     uint16_t counterClass = 1;
823     uint16_t counterInterpolation = 1;
824     double counterMultiplier = 1234.567f;
825     const std::string counterName = "some_invalid_counter";
826     const std::string counterDescription = "a valid description";
827     const std::string counterUnits = "Mrad s2"; // Invalid units
828     const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
829                                                          counterUid,
830                                                          maxCounterUid,
831                                                          counterClass,
832                                                          counterInterpolation,
833                                                          counterMultiplier,
834                                                          counterName,
835                                                          counterDescription,
836                                                          counterUnits,
837                                                          deviceUid,
838                                                          counterSetUid);
839     ARMNN_ASSERT(counter);
840
841     // Create an event record
842     SendCounterPacket::EventRecord eventRecord;
843     std::string errorMessage;
844     bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
845
846     BOOST_CHECK(!result);
847     BOOST_CHECK(!errorMessage.empty());
848     BOOST_CHECK(eventRecord.empty());
849 }
850
851 BOOST_AUTO_TEST_CASE(CreateCategoryRecordTest)
852 {
853     MockBufferManager mockBuffer(0);
854     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
855
856     // Create a category for testing
857     const std::string categoryName = "some_category";
858     const CategoryPtr category = std::make_unique<Category>(categoryName);
859     ARMNN_ASSERT(category);
860     category->m_Counters = { 11u, 23u, 5670u };
861
862     // Create a collection of counters
863     Counters counters;
864     counters.insert(std::make_pair<uint16_t, CounterPtr>(11,
865                                                          CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
866                                                                                 0,
867                                                                                 11,
868                                                                                 0,
869                                                                                 0,
870                                                                                 534.0003f,
871                                                                                 "counter1",
872                                                                                 "the first counter",
873                                                                                 "millipi2",
874                                                                                 0,
875                                                                                 0))));
876     counters.insert(std::make_pair<uint16_t, CounterPtr>(23,
877                                                          CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
878                                                                                 1,
879                                                                                 23,
880                                                                                 0,
881                                                                                 1,
882                                                                                 534.0003f,
883                                                                                 "this is counter 2",
884                                                                                 "the second counter",
885                                                                                 "",
886                                                                                 0,
887                                                                                 0))));
888     counters.insert(std::make_pair<uint16_t, CounterPtr>(5670,
889                                                          CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
890                                                                                 2,
891                                                                                 5670,
892                                                                                 0,
893                                                                                 0,
894                                                                                 534.0003f,
895                                                                                 "and this is number 3",
896                                                                                 "the third counter",
897                                                                                 "blah_per_second",
898                                                                                 0,
899                                                                                 0))));
900     Counter* counter1 = counters.find(11)->second.get();
901     Counter* counter2 = counters.find(23)->second.get();
902     Counter* counter3 = counters.find(5670)->second.get();
903     ARMNN_ASSERT(counter1);
904     ARMNN_ASSERT(counter2);
905     ARMNN_ASSERT(counter3);
906     uint16_t categoryEventCount = boost::numeric_cast<uint16_t>(counters.size());
907
908     // Create a category record
909     SendCounterPacket::CategoryRecord categoryRecord;
910     std::string errorMessage;
911     bool result = sendCounterPacketTest.CreateCategoryRecordTest(category, counters, categoryRecord, errorMessage);
912
913     BOOST_CHECK(result);
914     BOOST_CHECK(errorMessage.empty());
915     BOOST_CHECK(categoryRecord.size() == 79); // Size in words: header [3] + event pointer table [3] +
916                                               //                category name [5] + event records [68 = 22 + 20 + 26]
917
918     uint16_t categoryRecordWord1[]
919     {
920         static_cast<uint16_t>(categoryRecord[0] >> 16),
921         static_cast<uint16_t>(categoryRecord[0])
922     };
923     BOOST_CHECK(categoryRecordWord1[0] == categoryEventCount); // event_count
924     BOOST_CHECK(categoryRecordWord1[1] == 0); // reserved
925
926     size_t uint32_t_size = sizeof(uint32_t);
927
928     ARMNN_NO_CONVERSION_WARN_BEGIN
929     uint32_t eventPointerTableOffset = 0; // The event pointer table is the first item in pool
930     uint32_t categoryNameOffset = eventPointerTableOffset + // Event pointer table offset
931                                   categoryEventCount * uint32_t_size; // The size of the event pointer table
932     ARMNN_NO_CONVERSION_WARN_END
933
934     BOOST_CHECK(categoryRecord[1] == eventPointerTableOffset); // event_pointer_table_offset
935     BOOST_CHECK(categoryRecord[2] == categoryNameOffset); // name_offset
936
937     auto categoryRecordPool = reinterpret_cast<unsigned char*>(categoryRecord.data() + 3u); // The start of the pool
938
939     // The event pointer table
940     uint32_t eventRecord0Offset = categoryRecordPool[eventPointerTableOffset + 0 * uint32_t_size];
941     uint32_t eventRecord1Offset = categoryRecordPool[eventPointerTableOffset + 1 * uint32_t_size];
942     uint32_t eventRecord2Offset = categoryRecordPool[eventPointerTableOffset + 2 * uint32_t_size];
943     BOOST_CHECK(eventRecord0Offset == 32);
944     BOOST_CHECK(eventRecord1Offset == 120);
945     BOOST_CHECK(eventRecord2Offset == 200);
946
947     // The length of the SWTrace namestring (name)
948     BOOST_CHECK(categoryRecordPool[categoryNameOffset] == categoryName.size() + 1);
949     // The category name
950     BOOST_CHECK(std::memcmp(categoryRecordPool +
951                             categoryNameOffset + // Offset
952                             uint32_t_size, // The length of the name
953                             categoryName.data(),
954                             categoryName.size()) == 0); // name
955     // The null-terminator at the end of the name
956     BOOST_CHECK(categoryRecordPool[categoryNameOffset + uint32_t_size + categoryName.size()] == '\0');
957
958     // For brevity, checking only the UIDs, max counter UIDs and names of the counters in the event records,
959     // as the event records already have a number of unit tests dedicated to them
960
961     // Counter1 UID and max counter UID
962     uint16_t eventRecord0Word0[2] = { 0u, 0u };
963     std::memcpy(eventRecord0Word0, categoryRecordPool + eventRecord0Offset, sizeof(eventRecord0Word0));
964     BOOST_CHECK(eventRecord0Word0[0] == counter1->m_Uid);
965     BOOST_CHECK(eventRecord0Word0[1] == counter1->m_MaxCounterUid);
966
967     // Counter1 name
968     uint32_t counter1NameOffset = 0;
969     std::memcpy(&counter1NameOffset, categoryRecordPool + eventRecord0Offset + 5u * uint32_t_size, uint32_t_size);
970     BOOST_CHECK(counter1NameOffset == 0);
971     // The length of the SWTrace string (name)
972     BOOST_CHECK(categoryRecordPool[eventRecord0Offset + // Offset to the event record
973                                    8u * uint32_t_size + // Offset to the event record pool
974                                    counter1NameOffset   // Offset to the name of the counter
975                                   ] == counter1->m_Name.size() + 1); // The length of the name including the
976                                                                      // null-terminator
977     // The counter1 name
978     BOOST_CHECK(std::memcmp(categoryRecordPool + // The beginning of the category pool
979                             eventRecord0Offset + // Offset to the event record
980                             8u * uint32_t_size + // Offset to the event record pool
981                             counter1NameOffset + // Offset to the name of the counter
982                             uint32_t_size,       // The length of the name
983                             counter1->m_Name.data(),
984                             counter1->m_Name.size()) == 0); // name
985     // The null-terminator at the end of the counter1 name
986     BOOST_CHECK(categoryRecordPool[eventRecord0Offset +    // Offset to the event record
987                                    8u * uint32_t_size +    // Offset to the event record pool
988                                    counter1NameOffset +    // Offset to the name of the counter
989                                    uint32_t_size +         // The length of the name
990                                    counter1->m_Name.size() // The name of the counter
991                                    ] == '\0');
992
993     // Counter2 name
994     uint32_t counter2NameOffset = 0;
995     std::memcpy(&counter2NameOffset, categoryRecordPool + eventRecord1Offset + 5u * uint32_t_size, uint32_t_size);
996     BOOST_CHECK(counter2NameOffset == 0);
997     // The length of the SWTrace string (name)
998     BOOST_CHECK(categoryRecordPool[eventRecord1Offset + // Offset to the event record
999                                    8u * uint32_t_size + // Offset to the event record pool
1000                                    counter2NameOffset   // Offset to the name of the counter
1001                                   ] == counter2->m_Name.size() + 1); // The length of the name including the
1002                                                                      // null-terminator
1003     // The counter2 name
1004     BOOST_CHECK(std::memcmp(categoryRecordPool + // The beginning of the category pool
1005                             eventRecord1Offset + // Offset to the event record
1006                             8u * uint32_t_size + // Offset to the event record pool
1007                             counter2NameOffset + // Offset to the name of the counter
1008                             uint32_t_size,       // The length of the name
1009                             counter2->m_Name.data(),
1010                             counter2->m_Name.size()) == 0); // name
1011     // The null-terminator at the end of the counter2 name
1012     BOOST_CHECK(categoryRecordPool[eventRecord1Offset +    // Offset to the event record
1013                                    8u * uint32_t_size +    // Offset to the event record pool
1014                                    counter2NameOffset +    // Offset to the name of the counter
1015                                    uint32_t_size +         // The length of the name
1016                                    counter2->m_Name.size() // The name of the counter
1017                                    ] == '\0');
1018
1019     // Counter3 name
1020     uint32_t counter3NameOffset = 0;
1021     std::memcpy(&counter3NameOffset, categoryRecordPool + eventRecord2Offset + 5u * uint32_t_size, uint32_t_size);
1022     BOOST_CHECK(counter3NameOffset == 0);
1023     // The length of the SWTrace string (name)
1024     BOOST_CHECK(categoryRecordPool[eventRecord2Offset + // Offset to the event record
1025                                    8u * uint32_t_size + // Offset to the event record pool
1026                                    counter3NameOffset   // Offset to the name of the counter
1027                                   ] == counter3->m_Name.size() + 1); // The length of the name including the
1028                                                                      // null-terminator
1029     // The counter3 name
1030     BOOST_CHECK(std::memcmp(categoryRecordPool + // The beginning of the category pool
1031                             eventRecord2Offset + // Offset to the event record
1032                             8u * uint32_t_size + // Offset to the event record pool
1033                             counter3NameOffset + // Offset to the name of the counter
1034                             uint32_t_size,       // The length of the name
1035                             counter3->m_Name.data(),
1036                             counter3->m_Name.size()) == 0); // name
1037     // The null-terminator at the end of the counter3 name
1038     BOOST_CHECK(categoryRecordPool[eventRecord2Offset +    // Offset to the event record
1039                                    8u * uint32_t_size +    // Offset to the event record pool
1040                                    counter3NameOffset +    // Offset to the name of the counter
1041                                    uint32_t_size +         // The length of the name
1042                                    counter3->m_Name.size() // The name of the counter
1043                                    ] == '\0');
1044 }
1045
1046 BOOST_AUTO_TEST_CASE(CreateInvalidCategoryRecordTest1)
1047 {
1048     MockBufferManager mockBuffer(0);
1049     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
1050
1051     // Create a category for testing
1052     const std::string categoryName = "some invalid category";
1053     const CategoryPtr category = std::make_unique<Category>(categoryName);
1054     BOOST_CHECK(category);
1055
1056     // Create a category record
1057     Counters counters;
1058     SendCounterPacket::CategoryRecord categoryRecord;
1059     std::string errorMessage;
1060     bool result = sendCounterPacketTest.CreateCategoryRecordTest(category, counters, categoryRecord, errorMessage);
1061
1062     BOOST_CHECK(!result);
1063     BOOST_CHECK(!errorMessage.empty());
1064     BOOST_CHECK(categoryRecord.empty());
1065 }
1066
1067 BOOST_AUTO_TEST_CASE(CreateInvalidCategoryRecordTest2)
1068 {
1069     MockBufferManager mockBuffer(0);
1070     SendCounterPacketTest sendCounterPacketTest(mockBuffer);
1071
1072     // Create a category for testing
1073     const std::string categoryName = "some_category";
1074     const CategoryPtr category = std::make_unique<Category>(categoryName);
1075     BOOST_CHECK(category);
1076     category->m_Counters = { 11u, 23u, 5670u };
1077
1078     // Create a collection of counters
1079     Counters counters;
1080     counters.insert(std::make_pair<uint16_t, CounterPtr>(11,
1081                                                          CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
1082                                                                                 11,
1083                                                                                 1234,
1084                                                                                 0,
1085                                                                                 1,
1086                                                                                 534.0003f,
1087                                                                                 "count€r1", // Invalid name
1088                                                                                 "the first counter",
1089                                                                                 "millipi2",
1090                                                                                 0,
1091                                                                                 0))));
1092
1093     Counter* counter1 = counters.find(11)->second.get();
1094     BOOST_CHECK(counter1);
1095
1096     // Create a category record
1097     SendCounterPacket::CategoryRecord categoryRecord;
1098     std::string errorMessage;
1099     bool result = sendCounterPacketTest.CreateCategoryRecordTest(category, counters, categoryRecord, errorMessage);
1100
1101     BOOST_CHECK(!result);
1102     BOOST_CHECK(!errorMessage.empty());
1103     BOOST_CHECK(categoryRecord.empty());
1104 }
1105
1106 BOOST_AUTO_TEST_CASE(SendCounterDirectoryPacketTest1)
1107 {
1108     // The counter directory used for testing
1109     CounterDirectory counterDirectory;
1110
1111     // Register a device
1112     const std::string device1Name = "device1";
1113     const Device* device1 = nullptr;
1114     BOOST_CHECK_NO_THROW(device1 = counterDirectory.RegisterDevice(device1Name, 3));
1115     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
1116     BOOST_CHECK(device1);
1117
1118     // Register a device
1119     const std::string device2Name = "device2";
1120     const Device* device2 = nullptr;
1121     BOOST_CHECK_NO_THROW(device2 = counterDirectory.RegisterDevice(device2Name));
1122     BOOST_CHECK(counterDirectory.GetDeviceCount() == 2);
1123     BOOST_CHECK(device2);
1124
1125     // Buffer with not enough space
1126     MockBufferManager mockBuffer(10);
1127     SendCounterPacket sendCounterPacket(mockBuffer);
1128     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory),
1129                       armnn::profiling::BufferExhaustion);
1130 }
1131
1132 BOOST_AUTO_TEST_CASE(SendCounterDirectoryPacketTest2)
1133 {
1134     // The counter directory used for testing
1135     CounterDirectory counterDirectory;
1136
1137     // Register a device
1138     const std::string device1Name = "device1";
1139     const Device* device1 = nullptr;
1140     BOOST_CHECK_NO_THROW(device1 = counterDirectory.RegisterDevice(device1Name, 3));
1141     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
1142     BOOST_CHECK(device1);
1143
1144     // Register a device
1145     const std::string device2Name = "device2";
1146     const Device* device2 = nullptr;
1147     BOOST_CHECK_NO_THROW(device2 = counterDirectory.RegisterDevice(device2Name));
1148     BOOST_CHECK(counterDirectory.GetDeviceCount() == 2);
1149     BOOST_CHECK(device2);
1150
1151     // Register a counter set
1152     const std::string counterSet1Name = "counterset1";
1153     const CounterSet* counterSet1 = nullptr;
1154     BOOST_CHECK_NO_THROW(counterSet1 = counterDirectory.RegisterCounterSet(counterSet1Name));
1155     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1156     BOOST_CHECK(counterSet1);
1157
1158     // Register a category associated to "device1" and "counterset1"
1159     const std::string category1Name = "category1";
1160     const Category* category1 = nullptr;
1161     BOOST_CHECK_NO_THROW(category1 = counterDirectory.RegisterCategory(category1Name));
1162     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
1163     BOOST_CHECK(category1);
1164
1165     // Register a category not associated to "device2" but no counter set
1166     const std::string category2Name = "category2";
1167     const Category* category2 = nullptr;
1168     BOOST_CHECK_NO_THROW(category2 = counterDirectory.RegisterCategory(category2Name));
1169     BOOST_CHECK(counterDirectory.GetCategoryCount() == 2);
1170     BOOST_CHECK(category2);
1171
1172     uint16_t numberOfCores = 4;
1173
1174     // Register a counter associated to "category1"
1175     const Counter* counter1 = nullptr;
1176     BOOST_CHECK_NO_THROW(counter1 = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1177                                                                      0,
1178                                                                      category1Name,
1179                                                                      0,
1180                                                                      1,
1181                                                                      123.45f,
1182                                                                      "counter1",
1183                                                                      "counter1description",
1184                                                                      std::string("counter1units"),
1185                                                                      numberOfCores));
1186     BOOST_CHECK(counterDirectory.GetCounterCount() == 4);
1187     BOOST_CHECK(counter1);
1188
1189     // Register a counter associated to "category1"
1190     const Counter* counter2 = nullptr;
1191     BOOST_CHECK_NO_THROW(counter2 = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1192                                                                      4,
1193                                                                      category1Name,
1194                                                                      1,
1195                                                                      0,
1196                                                                      330.1245656765f,
1197                                                                      "counter2",
1198                                                                      "counter2description",
1199                                                                      std::string("counter2units"),
1200                                                                      armnn::EmptyOptional(),
1201                                                                      device2->m_Uid,
1202                                                                      0));
1203     BOOST_CHECK(counterDirectory.GetCounterCount() == 5);
1204     BOOST_CHECK(counter2);
1205
1206     // Register a counter associated to "category2"
1207     const Counter* counter3 = nullptr;
1208     BOOST_CHECK_NO_THROW(counter3 = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1209                                                                      5,
1210                                                                      category2Name,
1211                                                                      1,
1212                                                                      1,
1213                                                                      0.0000045399f,
1214                                                                      "counter3",
1215                                                                      "counter3description",
1216                                                                      armnn::EmptyOptional(),
1217                                                                      numberOfCores,
1218                                                                      device2->m_Uid,
1219                                                                      counterSet1->m_Uid));
1220     BOOST_CHECK(counterDirectory.GetCounterCount() == 9);
1221     BOOST_CHECK(counter3);
1222
1223     // Buffer with enough space
1224     MockBufferManager mockBuffer(1024);
1225     SendCounterPacket sendCounterPacket(mockBuffer);
1226     BOOST_CHECK_NO_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory));
1227
1228     // Get the readable buffer
1229     auto readBuffer = mockBuffer.GetReadableBuffer();
1230
1231     // Check the packet header
1232     const uint32_t packetHeaderWord0 = ReadUint32(readBuffer, 0);
1233     const uint32_t packetHeaderWord1 = ReadUint32(readBuffer, 4);
1234     BOOST_TEST(((packetHeaderWord0 >> 26) & 0x3F) == 0);  // packet_family
1235     BOOST_TEST(((packetHeaderWord0 >> 16) & 0x3FF) == 2); // packet_id
1236     BOOST_TEST(packetHeaderWord1 == 432);                 // data_length
1237
1238     // Check the body header
1239     const uint32_t bodyHeaderWord0 = ReadUint32(readBuffer,  8);
1240     const uint32_t bodyHeaderWord1 = ReadUint32(readBuffer, 12);
1241     const uint32_t bodyHeaderWord2 = ReadUint32(readBuffer, 16);
1242     const uint32_t bodyHeaderWord3 = ReadUint32(readBuffer, 20);
1243     const uint32_t bodyHeaderWord4 = ReadUint32(readBuffer, 24);
1244     const uint32_t bodyHeaderWord5 = ReadUint32(readBuffer, 28);
1245     const uint16_t deviceRecordCount     = static_cast<uint16_t>(bodyHeaderWord0 >> 16);
1246     const uint16_t counterSetRecordCount = static_cast<uint16_t>(bodyHeaderWord2 >> 16);
1247     const uint16_t categoryRecordCount   = static_cast<uint16_t>(bodyHeaderWord4 >> 16);
1248     BOOST_TEST(deviceRecordCount == 2);                      // device_records_count
1249     BOOST_TEST(bodyHeaderWord1 == bodyHeaderSize * 4);           // device_records_pointer_table_offset
1250     BOOST_TEST(counterSetRecordCount == 1);                  // counter_set_count
1251     BOOST_TEST(bodyHeaderWord3 == 8 + bodyHeaderSize * 4);       // counter_set_pointer_table_offset
1252     BOOST_TEST(categoryRecordCount == 2);                    // categories_count
1253     BOOST_TEST(bodyHeaderWord5 == 12 + bodyHeaderSize * 4);      // categories_pointer_table_offset
1254
1255     // Check the device records pointer table
1256     const uint32_t deviceRecordOffset0 = ReadUint32(readBuffer, 32);
1257     const uint32_t deviceRecordOffset1 = ReadUint32(readBuffer, 36);
1258     BOOST_TEST(deviceRecordOffset0 ==  0); // Device record offset for "device1"
1259     BOOST_TEST(deviceRecordOffset1 == 20); // Device record offset for "device2"
1260
1261     // Check the counter set pointer table
1262     const uint32_t counterSetRecordOffset0 = ReadUint32(readBuffer, 40);
1263     BOOST_TEST(counterSetRecordOffset0 == 40); // Counter set record offset for "counterset1"
1264
1265     // Check the category pointer table
1266     const uint32_t categoryRecordOffset0 = ReadUint32(readBuffer, 44);
1267     const uint32_t categoryRecordOffset1 = ReadUint32(readBuffer, 48);
1268     BOOST_TEST(categoryRecordOffset0 ==  64); // Category record offset for "category1"
1269     BOOST_TEST(categoryRecordOffset1 == 168); // Category record offset for "category2"
1270
1271     // Get the device record pool offset
1272     const uint32_t uint32_t_size = sizeof(uint32_t);
1273     const uint32_t packetBodyPoolOffset = 2u * uint32_t_size +                   // packet_header
1274                                           bodyHeaderWord1 +                      // body_header
1275                                           deviceRecordCount * uint32_t_size +    // Size of device_records_pointer_table
1276                                           counterSetRecordCount * uint32_t_size  // Size of counter_set_pointer_table
1277                                           + categoryRecordCount * uint32_t_size; // Size of categories_pointer_table
1278
1279     // Device record structure/collection used for testing
1280     struct DeviceRecord
1281     {
1282         uint16_t    uid;
1283         uint16_t    cores;
1284         uint32_t    name_offset;
1285         uint32_t    name_length;
1286         std::string name;
1287     };
1288     std::vector<DeviceRecord> deviceRecords;
1289     const uint32_t deviceRecordsPointerTableOffset = 2u * uint32_t_size + // packet_header
1290                                                      bodyHeaderWord1;     // device_records_pointer_table_offset
1291
1292     const unsigned char* readData = readBuffer->GetReadableData();
1293
1294     for (uint32_t i = 0; i < deviceRecordCount; i++)
1295     {
1296         // Get the device record offset
1297         const uint32_t deviceRecordOffset = ReadUint32(readBuffer, deviceRecordsPointerTableOffset + i * uint32_t_size);
1298
1299         // Collect the data for the device record
1300         const uint32_t deviceRecordWord0 = ReadUint32(readBuffer,
1301                                                       packetBodyPoolOffset + deviceRecordOffset + 0 * uint32_t_size);
1302         const uint32_t deviceRecordWord1 = ReadUint32(readBuffer,
1303                                                       packetBodyPoolOffset + deviceRecordOffset + 1 * uint32_t_size);
1304         DeviceRecord deviceRecord;
1305         deviceRecord.uid = static_cast<uint16_t>(deviceRecordWord0 >> 16); // uid
1306         deviceRecord.cores = static_cast<uint16_t>(deviceRecordWord0);     // cores
1307         deviceRecord.name_offset = deviceRecordWord1;                      // name_offset
1308
1309         uint32_t deviceRecordPoolOffset = packetBodyPoolOffset +    // Packet body offset
1310                                           deviceRecordOffset +      // Device record offset
1311                                           2 * uint32_t_size +       // Device record header
1312                                           deviceRecord.name_offset; // Device name offset
1313         uint32_t deviceRecordNameLength = ReadUint32(readBuffer, deviceRecordPoolOffset);
1314         deviceRecord.name_length = deviceRecordNameLength; // name_length
1315         unsigned char deviceRecordNameNullTerminator = // name null-terminator
1316                 ReadUint8(readBuffer, deviceRecordPoolOffset + uint32_t_size + deviceRecordNameLength - 1);
1317         BOOST_CHECK(deviceRecordNameNullTerminator == '\0');
1318         std::vector<unsigned char> deviceRecordNameBuffer(deviceRecord.name_length - 1);
1319         std::memcpy(deviceRecordNameBuffer.data(),
1320                     readData + deviceRecordPoolOffset + uint32_t_size, deviceRecordNameBuffer.size());
1321         deviceRecord.name.assign(deviceRecordNameBuffer.begin(), deviceRecordNameBuffer.end()); // name
1322
1323         deviceRecords.push_back(deviceRecord);
1324     }
1325
1326     // Check that the device records are correct
1327     BOOST_CHECK(deviceRecords.size() == 2);
1328     for (const DeviceRecord& deviceRecord : deviceRecords)
1329     {
1330         const Device* device = counterDirectory.GetDevice(deviceRecord.uid);
1331         BOOST_CHECK(device);
1332         BOOST_CHECK(device->m_Uid   == deviceRecord.uid);
1333         BOOST_CHECK(device->m_Cores == deviceRecord.cores);
1334         BOOST_CHECK(device->m_Name  == deviceRecord.name);
1335     }
1336
1337     // Counter set record structure/collection used for testing
1338     struct CounterSetRecord
1339     {
1340         uint16_t    uid;
1341         uint16_t    count;
1342         uint32_t    name_offset;
1343         uint32_t    name_length;
1344         std::string name;
1345     };
1346     std::vector<CounterSetRecord> counterSetRecords;
1347     const uint32_t counterSetRecordsPointerTableOffset = 2u * uint32_t_size + // packet_header
1348                                                          bodyHeaderWord3;     // counter_set_pointer_table_offset
1349     for (uint32_t i = 0; i < counterSetRecordCount; i++)
1350     {
1351         // Get the counter set record offset
1352         const uint32_t counterSetRecordOffset = ReadUint32(readBuffer,
1353                                                            counterSetRecordsPointerTableOffset + i * uint32_t_size);
1354
1355         // Collect the data for the counter set record
1356         const uint32_t counterSetRecordWord0 = ReadUint32(readBuffer,
1357                                                           packetBodyPoolOffset + counterSetRecordOffset +
1358                                                           0 * uint32_t_size);
1359         const uint32_t counterSetRecordWord1 = ReadUint32(readBuffer,
1360                                                           packetBodyPoolOffset + counterSetRecordOffset +
1361                                                           1 * uint32_t_size);
1362         CounterSetRecord counterSetRecord;
1363         counterSetRecord.uid = static_cast<uint16_t>(counterSetRecordWord0 >> 16); // uid
1364         counterSetRecord.count = static_cast<uint16_t>(counterSetRecordWord0);     // count
1365         counterSetRecord.name_offset = counterSetRecordWord1;                      // name_offset
1366
1367         uint32_t counterSetRecordPoolOffset = packetBodyPoolOffset +        // Packet body offset
1368                                               counterSetRecordOffset +      // Counter set record offset
1369                                               2 * uint32_t_size +           // Counter set record header
1370                                               counterSetRecord.name_offset; // Counter set name offset
1371         uint32_t counterSetRecordNameLength = ReadUint32(readBuffer, counterSetRecordPoolOffset);
1372         counterSetRecord.name_length = counterSetRecordNameLength; // name_length
1373         unsigned char counterSetRecordNameNullTerminator = // name null-terminator
1374                 ReadUint8(readBuffer, counterSetRecordPoolOffset + uint32_t_size + counterSetRecordNameLength - 1);
1375         BOOST_CHECK(counterSetRecordNameNullTerminator == '\0');
1376         std::vector<unsigned char> counterSetRecordNameBuffer(counterSetRecord.name_length - 1);
1377         std::memcpy(counterSetRecordNameBuffer.data(),
1378                     readData + counterSetRecordPoolOffset + uint32_t_size, counterSetRecordNameBuffer.size());
1379         counterSetRecord.name.assign(counterSetRecordNameBuffer.begin(), counterSetRecordNameBuffer.end()); // name
1380
1381         counterSetRecords.push_back(counterSetRecord);
1382     }
1383
1384     // Check that the counter set records are correct
1385     BOOST_CHECK(counterSetRecords.size() == 1);
1386     for (const CounterSetRecord& counterSetRecord : counterSetRecords)
1387     {
1388         const CounterSet* counterSet = counterDirectory.GetCounterSet(counterSetRecord.uid);
1389         BOOST_CHECK(counterSet);
1390         BOOST_CHECK(counterSet->m_Uid   == counterSetRecord.uid);
1391         BOOST_CHECK(counterSet->m_Count == counterSetRecord.count);
1392         BOOST_CHECK(counterSet->m_Name  == counterSetRecord.name);
1393     }
1394
1395     // Event record structure/collection used for testing
1396     struct EventRecord
1397     {
1398         uint16_t    counter_uid;
1399         uint16_t    max_counter_uid;
1400         uint16_t    device;
1401         uint16_t    counter_set;
1402         uint16_t    counter_class;
1403         uint16_t    interpolation;
1404         double      multiplier;
1405         uint32_t    name_offset;
1406         uint32_t    name_length;
1407         std::string name;
1408         uint32_t    description_offset;
1409         uint32_t    description_length;
1410         std::string description;
1411         uint32_t    units_offset;
1412         uint32_t    units_length;
1413         std::string units;
1414     };
1415     // Category record structure/collection used for testing
1416     struct CategoryRecord
1417     {
1418         uint16_t                 event_count;
1419         uint32_t                 event_pointer_table_offset;
1420         uint32_t                 name_offset;
1421         uint32_t                 name_length;
1422         std::string              name;
1423         std::vector<uint32_t>    event_pointer_table;
1424         std::vector<EventRecord> event_records;
1425     };
1426     std::vector<CategoryRecord> categoryRecords;
1427     const uint32_t categoryRecordsPointerTableOffset = 2u * uint32_t_size + // packet_header
1428                                                        bodyHeaderWord5;    // categories_pointer_table_offset
1429     for (uint32_t i = 0; i < categoryRecordCount; i++)
1430     {
1431         // Get the category record offset
1432         const uint32_t categoryRecordOffset = ReadUint32(readBuffer, categoryRecordsPointerTableOffset +
1433                                                          i * uint32_t_size);
1434
1435         // Collect the data for the category record
1436         const uint32_t categoryRecordWord1 = ReadUint32(readBuffer,
1437                                                         packetBodyPoolOffset + categoryRecordOffset +
1438                                                         0 * uint32_t_size);
1439         const uint32_t categoryRecordWord2 = ReadUint32(readBuffer,
1440                                                         packetBodyPoolOffset + categoryRecordOffset +
1441                                                         1 * uint32_t_size);
1442         const uint32_t categoryRecordWord3 = ReadUint32(readBuffer,
1443                                                         packetBodyPoolOffset + categoryRecordOffset +
1444                                                         2 * uint32_t_size);
1445         CategoryRecord categoryRecord;
1446         categoryRecord.event_count = static_cast<uint16_t>(categoryRecordWord1 >> 16); // event_count
1447         categoryRecord.event_pointer_table_offset = categoryRecordWord2;               // event_pointer_table_offset
1448         categoryRecord.name_offset = categoryRecordWord3;                              // name_offset
1449
1450         uint32_t categoryRecordPoolOffset = packetBodyPoolOffset +      // Packet body offset
1451                                             categoryRecordOffset +      // Category record offset
1452                                             3 * uint32_t_size;          // Category record header
1453
1454         uint32_t categoryRecordNameLength = ReadUint32(readBuffer,
1455                                                        categoryRecordPoolOffset + categoryRecord.name_offset);
1456         categoryRecord.name_length = categoryRecordNameLength; // name_length
1457         unsigned char categoryRecordNameNullTerminator =
1458                 ReadUint8(readBuffer,
1459                           categoryRecordPoolOffset +
1460                           categoryRecord.name_offset +
1461                           uint32_t_size +
1462                           categoryRecordNameLength - 1); // name null-terminator
1463         BOOST_CHECK(categoryRecordNameNullTerminator == '\0');
1464         std::vector<unsigned char> categoryRecordNameBuffer(categoryRecord.name_length - 1);
1465         std::memcpy(categoryRecordNameBuffer.data(),
1466                     readData +
1467                     categoryRecordPoolOffset +
1468                     categoryRecord.name_offset +
1469                     uint32_t_size,
1470                     categoryRecordNameBuffer.size());
1471         categoryRecord.name.assign(categoryRecordNameBuffer.begin(), categoryRecordNameBuffer.end()); // name
1472
1473         categoryRecord.event_pointer_table.resize(categoryRecord.event_count);
1474         for (uint32_t eventIndex = 0; eventIndex < categoryRecord.event_count; eventIndex++)
1475         {
1476             uint32_t eventRecordOffset = ReadUint32(readBuffer,
1477                                                     categoryRecordPoolOffset +
1478                                                     categoryRecord.event_pointer_table_offset +
1479                                                     eventIndex * uint32_t_size);
1480             categoryRecord.event_pointer_table[eventIndex] = eventRecordOffset;
1481
1482             // Collect the data for the event record
1483             const uint32_t eventRecordWord0  = ReadUint32(readBuffer,
1484                                                           categoryRecordPoolOffset + eventRecordOffset +
1485                                                           0 * uint32_t_size);
1486             const uint32_t eventRecordWord1  = ReadUint32(readBuffer,
1487                                                           categoryRecordPoolOffset + eventRecordOffset +
1488                                                           1 * uint32_t_size);
1489             const uint32_t eventRecordWord2  = ReadUint32(readBuffer,
1490                                                           categoryRecordPoolOffset + eventRecordOffset +
1491                                                           2 * uint32_t_size);
1492             const uint64_t eventRecordWord34 = ReadUint64(readBuffer,
1493                                                           categoryRecordPoolOffset + eventRecordOffset +
1494                                                           3 * uint32_t_size);
1495             const uint32_t eventRecordWord5 =  ReadUint32(readBuffer,
1496                                                           categoryRecordPoolOffset + eventRecordOffset +
1497                                                           5 * uint32_t_size);
1498             const uint32_t eventRecordWord6 = ReadUint32(readBuffer,
1499                                                          categoryRecordPoolOffset + eventRecordOffset +
1500                                                          6 * uint32_t_size);
1501             const uint32_t eventRecordWord7 = ReadUint32(readBuffer,
1502                                                          categoryRecordPoolOffset + eventRecordOffset +
1503                                                          7 * uint32_t_size);
1504             EventRecord eventRecord;
1505             eventRecord.counter_uid = static_cast<uint16_t>(eventRecordWord0);                     // counter_uid
1506             eventRecord.max_counter_uid = static_cast<uint16_t>(eventRecordWord0 >> 16);           // max_counter_uid
1507             eventRecord.device = static_cast<uint16_t>(eventRecordWord1 >> 16);                    // device
1508             eventRecord.counter_set = static_cast<uint16_t>(eventRecordWord1);                     // counter_set
1509             eventRecord.counter_class = static_cast<uint16_t>(eventRecordWord2 >> 16);             // class
1510             eventRecord.interpolation = static_cast<uint16_t>(eventRecordWord2);                   // interpolation
1511             std::memcpy(&eventRecord.multiplier, &eventRecordWord34, sizeof(eventRecord.multiplier)); // multiplier
1512             eventRecord.name_offset = static_cast<uint32_t>(eventRecordWord5);                     // name_offset
1513             eventRecord.description_offset = static_cast<uint32_t>(eventRecordWord6);              // description_offset
1514             eventRecord.units_offset = static_cast<uint32_t>(eventRecordWord7);                    // units_offset
1515
1516             uint32_t eventRecordPoolOffset = categoryRecordPoolOffset + // Category record pool offset
1517                                              eventRecordOffset +        // Event record offset
1518                                              8 * uint32_t_size;         // Event record header
1519
1520             uint32_t eventRecordNameLength = ReadUint32(readBuffer,
1521                                                         eventRecordPoolOffset + eventRecord.name_offset);
1522             eventRecord.name_length = eventRecordNameLength; // name_length
1523             unsigned char eventRecordNameNullTerminator =
1524                     ReadUint8(readBuffer,
1525                               eventRecordPoolOffset +
1526                               eventRecord.name_offset +
1527                               uint32_t_size +
1528                               eventRecordNameLength - 1); // name null-terminator
1529             BOOST_CHECK(eventRecordNameNullTerminator == '\0');
1530             std::vector<unsigned char> eventRecordNameBuffer(eventRecord.name_length - 1);
1531             std::memcpy(eventRecordNameBuffer.data(),
1532                         readData +
1533                         eventRecordPoolOffset +
1534                         eventRecord.name_offset +
1535                         uint32_t_size,
1536                         eventRecordNameBuffer.size());
1537             eventRecord.name.assign(eventRecordNameBuffer.begin(), eventRecordNameBuffer.end()); // name
1538
1539             uint32_t eventRecordDescriptionLength = ReadUint32(readBuffer,
1540                                                                eventRecordPoolOffset + eventRecord.description_offset);
1541             eventRecord.description_length = eventRecordDescriptionLength; // description_length
1542             unsigned char eventRecordDescriptionNullTerminator =
1543                     ReadUint8(readBuffer,
1544                               eventRecordPoolOffset +
1545                               eventRecord.description_offset +
1546                               uint32_t_size +
1547                               eventRecordDescriptionLength - 1); // description null-terminator
1548             BOOST_CHECK(eventRecordDescriptionNullTerminator == '\0');
1549             std::vector<unsigned char> eventRecordDescriptionBuffer(eventRecord.description_length - 1);
1550             std::memcpy(eventRecordDescriptionBuffer.data(),
1551                         readData +
1552                         eventRecordPoolOffset +
1553                         eventRecord.description_offset +
1554                         uint32_t_size,
1555                         eventRecordDescriptionBuffer.size());
1556             eventRecord.description.assign(eventRecordDescriptionBuffer.begin(),
1557                                            eventRecordDescriptionBuffer.end()); // description
1558
1559             if (eventRecord.units_offset > 0)
1560             {
1561                 uint32_t eventRecordUnitsLength = ReadUint32(readBuffer,
1562                                                              eventRecordPoolOffset + eventRecord.units_offset);
1563                 eventRecord.units_length = eventRecordUnitsLength; // units_length
1564                 unsigned char eventRecordUnitsNullTerminator =
1565                         ReadUint8(readBuffer,
1566                                   eventRecordPoolOffset +
1567                                   eventRecord.units_offset +
1568                                   uint32_t_size +
1569                                   eventRecordUnitsLength - 1); // units null-terminator
1570                 BOOST_CHECK(eventRecordUnitsNullTerminator == '\0');
1571                 std::vector<unsigned char> eventRecordUnitsBuffer(eventRecord.units_length - 1);
1572                 std::memcpy(eventRecordUnitsBuffer.data(),
1573                             readData +
1574                             eventRecordPoolOffset +
1575                             eventRecord.units_offset +
1576                             uint32_t_size,
1577                             eventRecordUnitsBuffer.size());
1578                 eventRecord.units.assign(eventRecordUnitsBuffer.begin(), eventRecordUnitsBuffer.end()); // units
1579             }
1580
1581             categoryRecord.event_records.push_back(eventRecord);
1582         }
1583
1584         categoryRecords.push_back(categoryRecord);
1585     }
1586
1587     // Check that the category records are correct
1588     BOOST_CHECK(categoryRecords.size() == 2);
1589     for (const CategoryRecord& categoryRecord : categoryRecords)
1590     {
1591         const Category* category = counterDirectory.GetCategory(categoryRecord.name);
1592         BOOST_CHECK(category);
1593         BOOST_CHECK(category->m_Name == categoryRecord.name);
1594         BOOST_CHECK(category->m_Counters.size() == categoryRecord.event_count + static_cast<size_t>(numberOfCores) -1);
1595         BOOST_CHECK(category->m_Counters.size() == categoryRecord.event_count + static_cast<size_t>(numberOfCores) -1);
1596
1597         // Check that the event records are correct
1598         for (const EventRecord& eventRecord : categoryRecord.event_records)
1599         {
1600             const Counter* counter = counterDirectory.GetCounter(eventRecord.counter_uid);
1601             BOOST_CHECK(counter);
1602             BOOST_CHECK(counter->m_MaxCounterUid == eventRecord.max_counter_uid);
1603             BOOST_CHECK(counter->m_DeviceUid == eventRecord.device);
1604             BOOST_CHECK(counter->m_CounterSetUid == eventRecord.counter_set);
1605             BOOST_CHECK(counter->m_Class == eventRecord.counter_class);
1606             BOOST_CHECK(counter->m_Interpolation == eventRecord.interpolation);
1607             BOOST_CHECK(counter->m_Multiplier == eventRecord.multiplier);
1608             BOOST_CHECK(counter->m_Name == eventRecord.name);
1609             BOOST_CHECK(counter->m_Description == eventRecord.description);
1610             BOOST_CHECK(counter->m_Units == eventRecord.units);
1611         }
1612     }
1613 }
1614
1615 BOOST_AUTO_TEST_CASE(SendCounterDirectoryPacketTest3)
1616 {
1617     // Using a mock counter directory that allows to register invalid objects
1618     MockCounterDirectory counterDirectory;
1619
1620     // Register an invalid device
1621     const std::string deviceName = "inv@lid dev!c€";
1622     const Device* device = nullptr;
1623     BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName, 3));
1624     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
1625     BOOST_CHECK(device);
1626
1627     // Buffer with enough space
1628     MockBufferManager mockBuffer(1024);
1629     SendCounterPacket sendCounterPacket(mockBuffer);
1630     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
1631 }
1632
1633 BOOST_AUTO_TEST_CASE(SendCounterDirectoryPacketTest4)
1634 {
1635     // Using a mock counter directory that allows to register invalid objects
1636     MockCounterDirectory counterDirectory;
1637
1638     // Register an invalid counter set
1639     const std::string counterSetName = "inv@lid count€rs€t";
1640     const CounterSet* counterSet = nullptr;
1641     BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1642     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1643     BOOST_CHECK(counterSet);
1644
1645     // Buffer with enough space
1646     MockBufferManager mockBuffer(1024);
1647     SendCounterPacket sendCounterPacket(mockBuffer);
1648     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
1649 }
1650
1651 BOOST_AUTO_TEST_CASE(SendCounterDirectoryPacketTest5)
1652 {
1653     // Using a mock counter directory that allows to register invalid objects
1654     MockCounterDirectory counterDirectory;
1655
1656     // Register an invalid category
1657     const std::string categoryName = "c@t€gory";
1658     const Category* category = nullptr;
1659     BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName));
1660     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
1661     BOOST_CHECK(category);
1662
1663     // Buffer with enough space
1664     MockBufferManager mockBuffer(1024);
1665     SendCounterPacket sendCounterPacket(mockBuffer);
1666     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
1667 }
1668
1669 BOOST_AUTO_TEST_CASE(SendCounterDirectoryPacketTest6)
1670 {
1671     // Using a mock counter directory that allows to register invalid objects
1672     MockCounterDirectory counterDirectory;
1673
1674     // Register an invalid device
1675     const std::string deviceName = "inv@lid dev!c€";
1676     const Device* device = nullptr;
1677     BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName, 3));
1678     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
1679     BOOST_CHECK(device);
1680
1681     // Register an invalid counter set
1682     const std::string counterSetName = "inv@lid count€rs€t";
1683     const CounterSet* counterSet = nullptr;
1684     BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1685     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1686     BOOST_CHECK(counterSet);
1687
1688     // Register an invalid category associated to an invalid device and an invalid counter set
1689     const std::string categoryName = "c@t€gory";
1690     const Category* category = nullptr;
1691     BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName));
1692     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
1693     BOOST_CHECK(category);
1694
1695     // Buffer with enough space
1696     MockBufferManager mockBuffer(1024);
1697     SendCounterPacket sendCounterPacket(mockBuffer);
1698     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
1699 }
1700
1701 BOOST_AUTO_TEST_CASE(SendCounterDirectoryPacketTest7)
1702 {
1703     // Using a mock counter directory that allows to register invalid objects
1704     MockCounterDirectory counterDirectory;
1705
1706     // Register an valid device
1707     const std::string deviceName = "valid device";
1708     const Device* device = nullptr;
1709     BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName, 3));
1710     BOOST_CHECK(counterDirectory.GetDeviceCount() == 1);
1711     BOOST_CHECK(device);
1712
1713     // Register an valid counter set
1714     const std::string counterSetName = "valid counterset";
1715     const CounterSet* counterSet = nullptr;
1716     BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1717     BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1);
1718     BOOST_CHECK(counterSet);
1719
1720     // Register an valid category associated to a valid device and a valid counter set
1721     const std::string categoryName = "category";
1722     const Category* category = nullptr;
1723     BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName));
1724     BOOST_CHECK(counterDirectory.GetCategoryCount() == 1);
1725     BOOST_CHECK(category);
1726
1727     // Register an invalid counter associated to a valid category
1728     const Counter* counter = nullptr;
1729     BOOST_CHECK_NO_THROW(counter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1730                                                                     0,
1731                                                                     categoryName,
1732                                                                     0,
1733                                                                     1,
1734                                                                     123.45f,
1735                                                                     "counter",
1736                                                                     "counter description",
1737                                                                     std::string("invalid counter units"),
1738                                                                     5,
1739                                                                     device->m_Uid,
1740                                                                     counterSet->m_Uid));
1741     BOOST_CHECK(counterDirectory.GetCounterCount() == 5);
1742     BOOST_CHECK(counter);
1743
1744     // Buffer with enough space
1745     MockBufferManager mockBuffer(1024);
1746     SendCounterPacket sendCounterPacket(mockBuffer);
1747     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
1748 }
1749
1750 BOOST_AUTO_TEST_CASE(SendThreadTest0)
1751 {
1752     ProfilingStateMachine profilingStateMachine;
1753     SetActiveProfilingState(profilingStateMachine);
1754
1755     MockProfilingConnection mockProfilingConnection;
1756     MockStreamCounterBuffer mockStreamCounterBuffer(0);
1757     SendCounterPacket sendCounterPacket(mockStreamCounterBuffer);
1758     SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
1759
1760     // Try to start the send thread many times, it must only start once
1761
1762     sendThread.Start(mockProfilingConnection);
1763     BOOST_CHECK(sendThread.IsRunning());
1764     sendThread.Start(mockProfilingConnection);
1765     sendThread.Start(mockProfilingConnection);
1766     sendThread.Start(mockProfilingConnection);
1767     sendThread.Start(mockProfilingConnection);
1768     BOOST_CHECK(sendThread.IsRunning());
1769
1770     sendThread.Stop();
1771     BOOST_CHECK(!sendThread.IsRunning());
1772 }
1773
1774 BOOST_AUTO_TEST_CASE(SendThreadTest1)
1775 {
1776     ProfilingStateMachine profilingStateMachine;
1777     SetActiveProfilingState(profilingStateMachine);
1778
1779     unsigned int totalWrittenSize = 0;
1780
1781     MockProfilingConnection mockProfilingConnection;
1782     MockStreamCounterBuffer mockStreamCounterBuffer(1024);
1783     SendCounterPacket sendCounterPacket(mockStreamCounterBuffer);
1784     SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
1785     sendThread.Start(mockProfilingConnection);
1786
1787     // Interleaving writes and reads to/from the buffer with pauses to test that the send thread actually waits for
1788     // something to become available for reading
1789
1790     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1791
1792     CounterDirectory counterDirectory;
1793     sendCounterPacket.SendStreamMetaDataPacket();
1794
1795     totalWrittenSize += GetStreamMetaDataPacketSize();
1796
1797     sendThread.SetReadyToRead();
1798
1799     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1800
1801     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
1802
1803     // Get the size of the Counter Directory Packet
1804     unsigned int counterDirectoryPacketSize = 32;
1805     totalWrittenSize += counterDirectoryPacketSize;
1806
1807     sendThread.SetReadyToRead();
1808
1809     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1810
1811     sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
1812                                                        {
1813                                                            {   1u,      23u },
1814                                                            {  33u, 1207623u }
1815                                                        });
1816
1817     // Get the size of the Periodic Counter Capture Packet
1818     unsigned int periodicCounterCapturePacketSize = 28;
1819     totalWrittenSize += periodicCounterCapturePacketSize;
1820
1821     sendThread.SetReadyToRead();
1822
1823     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1824
1825     sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
1826                                                        {
1827                                                            { 211u,     923u }
1828                                                        });
1829
1830     // Get the size of the Periodic Counter Capture Packet
1831     periodicCounterCapturePacketSize = 22;
1832     totalWrittenSize += periodicCounterCapturePacketSize;
1833
1834     sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
1835                                                        {
1836                                                            { 555u,      23u },
1837                                                            { 556u,       6u },
1838                                                            { 557u,  893454u },
1839                                                            { 558u, 1456623u },
1840                                                            { 559u,  571090u }
1841                                                        });
1842
1843     // Get the size of the Periodic Counter Capture Packet
1844     periodicCounterCapturePacketSize = 46;
1845     totalWrittenSize += periodicCounterCapturePacketSize;
1846
1847     sendCounterPacket.SendPeriodicCounterCapturePacket(997u,
1848                                                        {
1849                                                            {  88u,      11u },
1850                                                            {  96u,      22u },
1851                                                            {  97u,      33u },
1852                                                            { 999u,     444u }
1853                                                        });
1854
1855     // Get the size of the Periodic Counter Capture Packet
1856     periodicCounterCapturePacketSize = 40;
1857     totalWrittenSize += periodicCounterCapturePacketSize;
1858
1859     sendThread.SetReadyToRead();
1860
1861     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1862
1863     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
1864
1865     // Get the size of the Periodic Counter Capture Packet
1866     periodicCounterCapturePacketSize = 30;
1867     totalWrittenSize += periodicCounterCapturePacketSize;
1868
1869     sendThread.SetReadyToRead();
1870
1871     // To test an exact value of the "read size" in the mock buffer, wait to allow the send thread to
1872     // read all what's remaining in the buffer
1873     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1874
1875     sendThread.Stop();
1876
1877     BOOST_CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
1878     BOOST_CHECK(mockStreamCounterBuffer.GetReadableSize()  == totalWrittenSize);
1879     BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      == totalWrittenSize);
1880 }
1881
1882 BOOST_AUTO_TEST_CASE(SendThreadTest2)
1883 {
1884     ProfilingStateMachine profilingStateMachine;
1885     SetActiveProfilingState(profilingStateMachine);
1886
1887     unsigned int totalWrittenSize = 0;
1888
1889     MockProfilingConnection mockProfilingConnection;
1890     MockStreamCounterBuffer mockStreamCounterBuffer(1024);
1891     SendCounterPacket sendCounterPacket(mockStreamCounterBuffer);
1892     SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
1893     sendThread.Start(mockProfilingConnection);
1894
1895     // Adding many spurious "ready to read" signals throughout the test to check that the send thread is
1896     // capable of handling unnecessary read requests
1897
1898     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1899
1900     sendThread.SetReadyToRead();
1901
1902     CounterDirectory counterDirectory;
1903     sendCounterPacket.SendStreamMetaDataPacket();
1904
1905     totalWrittenSize += GetStreamMetaDataPacketSize();
1906
1907     sendThread.SetReadyToRead();
1908
1909     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1910
1911     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
1912
1913     // Get the size of the Counter Directory Packet
1914     unsigned int counterDirectoryPacketSize = 32;
1915     totalWrittenSize += counterDirectoryPacketSize;
1916
1917     sendThread.SetReadyToRead();
1918     sendThread.SetReadyToRead();
1919
1920     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1921
1922     sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
1923                                                        {
1924                                                            {   1u,      23u },
1925                                                            {  33u, 1207623u }
1926                                                        });
1927
1928     // Get the size of the Periodic Counter Capture Packet
1929     unsigned int periodicCounterCapturePacketSize = 28;
1930     totalWrittenSize += periodicCounterCapturePacketSize;
1931
1932     sendThread.SetReadyToRead();
1933
1934     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1935
1936     sendThread.SetReadyToRead();
1937     sendThread.SetReadyToRead();
1938     sendThread.SetReadyToRead();
1939
1940     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1941
1942     sendThread.SetReadyToRead();
1943     sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
1944                                                        {
1945                                                            { 211u,     923u }
1946                                                        });
1947
1948     // Get the size of the Periodic Counter Capture Packet
1949     periodicCounterCapturePacketSize = 22;
1950     totalWrittenSize += periodicCounterCapturePacketSize;
1951
1952     sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
1953                                                        {
1954                                                            { 555u,      23u },
1955                                                            { 556u,       6u },
1956                                                            { 557u,  893454u },
1957                                                            { 558u, 1456623u },
1958                                                            { 559u,  571090u }
1959                                                        });
1960
1961     // Get the size of the Periodic Counter Capture Packet
1962     periodicCounterCapturePacketSize = 46;
1963     totalWrittenSize += periodicCounterCapturePacketSize;
1964
1965     sendThread.SetReadyToRead();
1966     sendCounterPacket.SendPeriodicCounterCapturePacket(997u,
1967                                                        {
1968                                                            {  88u,      11u },
1969                                                            {  96u,      22u },
1970                                                            {  97u,      33u },
1971                                                            { 999u,     444u }
1972                                                        });
1973
1974     // Get the size of the Periodic Counter Capture Packet
1975     periodicCounterCapturePacketSize = 40;
1976     totalWrittenSize += periodicCounterCapturePacketSize;
1977
1978     sendThread.SetReadyToRead();
1979     sendThread.SetReadyToRead();
1980
1981     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1982
1983     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
1984
1985     // Get the size of the Periodic Counter Capture Packet
1986     periodicCounterCapturePacketSize = 30;
1987     totalWrittenSize += periodicCounterCapturePacketSize;
1988
1989     sendThread.SetReadyToRead();
1990
1991     // To test an exact value of the "read size" in the mock buffer, wait to allow the send thread to
1992     // read all what's remaining in the buffer
1993     sendThread.Stop();
1994
1995     BOOST_CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
1996     BOOST_CHECK(mockStreamCounterBuffer.GetReadableSize()  == totalWrittenSize);
1997     BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      == totalWrittenSize);
1998 }
1999
2000 BOOST_AUTO_TEST_CASE(SendThreadTest3)
2001 {
2002     ProfilingStateMachine profilingStateMachine;
2003     SetActiveProfilingState(profilingStateMachine);
2004
2005     unsigned int totalWrittenSize = 0;
2006
2007     MockProfilingConnection mockProfilingConnection;
2008     MockStreamCounterBuffer mockStreamCounterBuffer(1024);
2009     SendCounterPacket sendCounterPacket(mockStreamCounterBuffer);
2010     SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
2011     sendThread.Start(mockProfilingConnection);
2012
2013     // Not using pauses or "grace periods" to stress test the send thread
2014
2015     sendThread.SetReadyToRead();
2016
2017     CounterDirectory counterDirectory;
2018     sendCounterPacket.SendStreamMetaDataPacket();
2019
2020     totalWrittenSize += GetStreamMetaDataPacketSize();
2021
2022     sendThread.SetReadyToRead();
2023     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
2024
2025     // Get the size of the Counter Directory Packet
2026     unsigned int counterDirectoryPacketSize =32;
2027     totalWrittenSize += counterDirectoryPacketSize;
2028
2029     sendThread.SetReadyToRead();
2030     sendThread.SetReadyToRead();
2031     sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
2032                                                        {
2033                                                            {   1u,      23u },
2034                                                            {  33u, 1207623u }
2035                                                        });
2036
2037     // Get the size of the Periodic Counter Capture Packet
2038     unsigned int periodicCounterCapturePacketSize = 28;
2039     totalWrittenSize += periodicCounterCapturePacketSize;
2040
2041     sendThread.SetReadyToRead();
2042     sendThread.SetReadyToRead();
2043     sendThread.SetReadyToRead();
2044     sendThread.SetReadyToRead();
2045     sendThread.SetReadyToRead();
2046     sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
2047                                                        {
2048                                                            { 211u,     923u }
2049                                                        });
2050
2051     // Get the size of the Periodic Counter Capture Packet
2052     periodicCounterCapturePacketSize = 22;
2053     totalWrittenSize += periodicCounterCapturePacketSize;
2054
2055     sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
2056                                                        {
2057                                                            { 555u,      23u },
2058                                                            { 556u,       6u },
2059                                                            { 557u,  893454u },
2060                                                            { 558u, 1456623u },
2061                                                            { 559u,  571090u }
2062                                                        });
2063
2064     // Get the size of the Periodic Counter Capture Packet
2065     periodicCounterCapturePacketSize = 46;
2066     totalWrittenSize += periodicCounterCapturePacketSize;
2067
2068     sendThread.SetReadyToRead();
2069     sendThread.SetReadyToRead();
2070     sendCounterPacket.SendPeriodicCounterCapturePacket(997u,
2071                                                        {
2072                                                            {  88u,      11u },
2073                                                            {  96u,      22u },
2074                                                            {  97u,      33u },
2075                                                            { 999u,     444u }
2076                                                        });
2077
2078     // Get the size of the Periodic Counter Capture Packet
2079     periodicCounterCapturePacketSize = 40;
2080     totalWrittenSize += periodicCounterCapturePacketSize;
2081
2082     sendThread.SetReadyToRead();
2083     sendThread.SetReadyToRead();
2084     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
2085
2086     // Get the size of the Periodic Counter Capture Packet
2087     periodicCounterCapturePacketSize = 30;
2088     totalWrittenSize += periodicCounterCapturePacketSize;
2089
2090     sendThread.SetReadyToRead();
2091
2092     // Abruptly terminating the send thread, the amount of data sent may be less that the amount written (the send
2093     // thread is not guaranteed to flush the buffer)
2094     sendThread.Stop();
2095
2096     BOOST_CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
2097     BOOST_CHECK(mockStreamCounterBuffer.GetReadableSize()  <= totalWrittenSize);
2098     BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      <= totalWrittenSize);
2099     BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      <= mockStreamCounterBuffer.GetReadableSize());
2100     BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      <= mockStreamCounterBuffer.GetCommittedSize());
2101 }
2102
2103 BOOST_AUTO_TEST_CASE(SendCounterPacketTestWithSendThread)
2104 {
2105     ProfilingStateMachine profilingStateMachine;
2106     SetWaitingForAckProfilingState(profilingStateMachine);
2107
2108     MockProfilingConnection mockProfilingConnection;
2109     BufferManager bufferManager(1, 1024);
2110     SendCounterPacket sendCounterPacket(bufferManager);
2111     SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket, -1);
2112     sendThread.Start(mockProfilingConnection);
2113
2114     unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2115
2116     sendThread.Stop();
2117
2118     // check for packet in ProfilingConnection
2119     BOOST_CHECK(mockProfilingConnection.CheckForPacket({PacketType::StreamMetaData, streamMetadataPacketsize}) == 1);
2120
2121     SetActiveProfilingState(profilingStateMachine);
2122     sendThread.Start(mockProfilingConnection);
2123
2124     // SendCounterDirectoryPacket
2125     CounterDirectory counterDirectory;
2126     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
2127
2128     sendThread.Stop();
2129     unsigned int counterDirectoryPacketSize = 32;
2130     // check for packet in ProfilingConnection
2131     BOOST_CHECK(mockProfilingConnection.CheckForPacket(
2132         {PacketType::CounterDirectory, counterDirectoryPacketSize}) == 1);
2133
2134     sendThread.Start(mockProfilingConnection);
2135
2136     // SendPeriodicCounterCapturePacket
2137     sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
2138                                                        {
2139                                                            {   1u,      23u },
2140                                                            {  33u, 1207623u }
2141                                                        });
2142
2143     sendThread.Stop();
2144
2145     unsigned int periodicCounterCapturePacketSize = 28;
2146     BOOST_CHECK(mockProfilingConnection.CheckForPacket(
2147         {PacketType::PeriodicCounterCapture, periodicCounterCapturePacketSize}) == 1);
2148 }
2149
2150 BOOST_AUTO_TEST_CASE(SendThreadBufferTest)
2151 {
2152     ProfilingStateMachine profilingStateMachine;
2153     SetActiveProfilingState(profilingStateMachine);
2154
2155     MockProfilingConnection mockProfilingConnection;
2156     BufferManager bufferManager(3, 1024);
2157     SendCounterPacket sendCounterPacket(bufferManager);
2158     SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket, -1);
2159     sendThread.Start(mockProfilingConnection);
2160
2161     // SendStreamMetaDataPacket
2162     sendCounterPacket.SendStreamMetaDataPacket();
2163
2164     // Read data from the buffer
2165     // Buffer should become readable after commit by SendStreamMetaDataPacket
2166     auto packetBuffer = bufferManager.GetReadableBuffer();
2167     BOOST_TEST(packetBuffer.get());
2168
2169     unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2170     BOOST_TEST(packetBuffer->GetSize() == streamMetadataPacketsize);
2171
2172     // Recommit to be read by sendCounterPacket
2173     bufferManager.Commit(packetBuffer, streamMetadataPacketsize);
2174
2175     // SendCounterDirectoryPacket
2176     CounterDirectory counterDirectory;
2177     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
2178
2179     // SendPeriodicCounterCapturePacket
2180     sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
2181                                                        {
2182                                                            {   1u,      23u },
2183                                                            {  33u, 1207623u }
2184                                                        });
2185
2186     sendThread.Stop();
2187
2188     // The buffer is read by the send thread so it should not be in the readable buffer.
2189     auto readBuffer = bufferManager.GetReadableBuffer();
2190     BOOST_TEST(!readBuffer);
2191
2192     // Successfully reserved the buffer with requested size
2193     unsigned int reservedSize = 0;
2194     auto reservedBuffer = bufferManager.Reserve(512, reservedSize);
2195     BOOST_TEST(reservedSize == 512);
2196     BOOST_TEST(reservedBuffer.get());
2197
2198     const auto writtenDataSize = mockProfilingConnection.GetWrittenDataSize();
2199     const auto metaDataPacketCount =
2200             mockProfilingConnection.CheckForPacket({PacketType::StreamMetaData, streamMetadataPacketsize});
2201
2202     BOOST_TEST(metaDataPacketCount >= 1);
2203     BOOST_TEST(mockProfilingConnection.CheckForPacket({PacketType::CounterDirectory, 32}) == 1);
2204     BOOST_TEST(mockProfilingConnection.CheckForPacket({PacketType::PeriodicCounterCapture, 28}) == 1);
2205     // Check that we only received the packets we expected
2206     BOOST_TEST(metaDataPacketCount + 2 == writtenDataSize);
2207 }
2208
2209 BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket1)
2210 {
2211     ProfilingStateMachine profilingStateMachine;
2212
2213     MockProfilingConnection mockProfilingConnection;
2214     BufferManager bufferManager(3, 1024);
2215     SendCounterPacket sendCounterPacket(bufferManager);
2216     SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2217     sendThread.Start(mockProfilingConnection);
2218
2219     // The profiling state is set to "Uninitialized", so the send thread should throw an exception
2220     BOOST_CHECK_THROW(sendThread.Stop(), armnn::RuntimeException);
2221 }
2222
2223 BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket2)
2224 {
2225     ProfilingStateMachine profilingStateMachine;
2226     SetNotConnectedProfilingState(profilingStateMachine);
2227
2228     MockProfilingConnection mockProfilingConnection;
2229     BufferManager bufferManager(3, 1024);
2230     SendCounterPacket sendCounterPacket(bufferManager);
2231     SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2232     sendThread.Start(mockProfilingConnection);
2233
2234     // The profiling state is set to "NotConnected", so the send thread should throw an exception
2235     BOOST_CHECK_THROW(sendThread.Stop(), armnn::RuntimeException);
2236 }
2237
2238 BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket3)
2239 {
2240     ProfilingStateMachine profilingStateMachine;
2241     SetWaitingForAckProfilingState(profilingStateMachine);
2242
2243     unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2244
2245     MockProfilingConnection mockProfilingConnection;
2246     BufferManager bufferManager(3, 1024);
2247     SendCounterPacket sendCounterPacket(bufferManager);
2248     SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2249     sendThread.Start(mockProfilingConnection);
2250
2251     // The profiling state is set to "WaitingForAck", so the send thread should send a Stream Metadata packet
2252     // Wait for sendThread to join
2253     BOOST_CHECK_NO_THROW(sendThread.Stop());
2254
2255     // Check that the buffer contains at least one Stream Metadata packet and no other packets
2256     const auto writtenDataSize = mockProfilingConnection.GetWrittenDataSize();
2257
2258     BOOST_TEST(writtenDataSize >= 1);
2259     BOOST_TEST(mockProfilingConnection.CheckForPacket(
2260                   {PacketType::StreamMetaData, streamMetadataPacketsize}) == writtenDataSize);
2261 }
2262
2263 BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket4)
2264 {
2265     ProfilingStateMachine profilingStateMachine;
2266     SetWaitingForAckProfilingState(profilingStateMachine);
2267
2268     unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2269
2270     MockProfilingConnection mockProfilingConnection;
2271     BufferManager bufferManager(3, 1024);
2272     SendCounterPacket sendCounterPacket(bufferManager);
2273     SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2274     sendThread.Start(mockProfilingConnection);
2275
2276     // The profiling state is set to "WaitingForAck", so the send thread should send a Stream Metadata packet
2277     // Wait for sendThread to join
2278     sendThread.Stop();
2279
2280     sendThread.Start(mockProfilingConnection);
2281     // Check that the profiling state is still "WaitingForAck"
2282     BOOST_TEST((profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck));
2283
2284     // Check that the buffer contains at least one Stream Metadata packet
2285     BOOST_TEST(mockProfilingConnection.CheckForPacket({PacketType::StreamMetaData, streamMetadataPacketsize}) >= 1);
2286
2287     mockProfilingConnection.Clear();
2288
2289     sendThread.Stop();
2290     sendThread.Start(mockProfilingConnection);
2291
2292     // Try triggering a new buffer read
2293     sendThread.SetReadyToRead();
2294
2295     // Wait for sendThread to join
2296     BOOST_CHECK_NO_THROW(sendThread.Stop());
2297
2298     // Check that the profiling state is still "WaitingForAck"
2299     BOOST_TEST((profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck));
2300
2301     // Check that the buffer contains at least one Stream Metadata packet and no other packets
2302     const auto writtenDataSize = mockProfilingConnection.GetWrittenDataSize();
2303
2304     BOOST_TEST(writtenDataSize >= 1);
2305     BOOST_TEST(mockProfilingConnection.CheckForPacket(
2306                   {PacketType::StreamMetaData, streamMetadataPacketsize}) == writtenDataSize);
2307 }
2308
2309 BOOST_AUTO_TEST_SUITE_END()