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