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