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