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