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