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