ArmNN  NotReleased
ProfilingUtils.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "ProfilingUtils.hpp"
7 
8 #include <armnn/Version.hpp>
9 
10 #include <WallClockTimer.hpp>
11 
12 #include <boost/assert.hpp>
13 
14 #include <fstream>
15 #include <iostream>
16 #include <limits>
17 
18 namespace armnn
19 {
20 
21 namespace profiling
22 {
23 
24 namespace
25 {
26 
27 void ThrowIfCantGenerateNextUid(uint16_t uid, uint16_t cores = 0)
28 {
29  // Check that it is possible to generate the next UID without causing an overflow
30  switch (cores)
31  {
32  case 0:
33  case 1:
34  // Number of cores not specified or set to 1 (a value of zero indicates the device is not capable of
35  // running multiple parallel workloads and will not provide multiple streams of data for each event)
36  if (uid == std::numeric_limits<uint16_t>::max())
37  {
38  throw RuntimeException("Generating the next UID for profiling would result in an overflow");
39  }
40  break;
41  default: // cores > 1
42  // Multiple cores available, as max_counter_uid has to be set to: counter_uid + cores - 1, the maximum
43  // allowed value for a counter UID is consequently: uint16_t_max - cores + 1
44  if (uid >= std::numeric_limits<uint16_t>::max() - cores + 1)
45  {
46  throw RuntimeException("Generating the next UID for profiling would result in an overflow");
47  }
48  break;
49  }
50 }
51 
52 } // Anonymous namespace
53 
54 uint16_t GetNextUid(bool peekOnly)
55 {
56  // The UID used for profiling objects and events. The first valid UID is 1, as 0 is a reserved value
57  static uint16_t uid = 1;
58 
59  // Check that it is possible to generate the next UID without causing an overflow (throws in case of error)
60  ThrowIfCantGenerateNextUid(uid);
61 
62  if (peekOnly)
63  {
64  // Peek only
65  return uid;
66  }
67  else
68  {
69  // Get the next UID
70  return uid++;
71  }
72 }
73 
74 std::vector<uint16_t> GetNextCounterUids(uint16_t firstUid, uint16_t cores)
75 {
76  // Check that it is possible to generate the next counter UID without causing an overflow (throws in case of error)
77  ThrowIfCantGenerateNextUid(firstUid, cores);
78 
79  // Get the next counter UIDs
80  size_t counterUidsSize = cores == 0 ? 1 : cores;
81  std::vector<uint16_t> counterUids(counterUidsSize, 0);
82  for (size_t i = 0; i < counterUidsSize; i++)
83  {
84  counterUids[i] = firstUid++;
85  }
86  return counterUids;
87 }
88 
89 void WriteBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, const void* value, unsigned int valueSize)
90 {
91  BOOST_ASSERT(packetBuffer);
92 
93  WriteBytes(packetBuffer->GetWritableData(), offset, value, valueSize);
94 }
95 
96 uint32_t ConstructHeader(uint32_t packetFamily,
97  uint32_t packetId)
98 {
99  return ((packetFamily & 0x3F) << 26)|
100  ((packetId & 0x3FF) << 16);
101 }
102 
103 uint32_t ConstructHeader(uint32_t packetFamily,
104  uint32_t packetClass,
105  uint32_t packetType)
106 {
107  return ((packetFamily & 0x3F) << 26)|
108  ((packetClass & 0x3FF) << 19)|
109  ((packetType & 0x3FFF) << 16);
110 }
111 
112 void WriteUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint64_t value)
113 {
114  BOOST_ASSERT(packetBuffer);
115 
116  WriteUint64(packetBuffer->GetWritableData(), offset, value);
117 }
118 
119 void WriteUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint32_t value)
120 {
121  BOOST_ASSERT(packetBuffer);
122 
123  WriteUint32(packetBuffer->GetWritableData(), offset, value);
124 }
125 
126 void WriteUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint16_t value)
127 {
128  BOOST_ASSERT(packetBuffer);
129 
130  WriteUint16(packetBuffer->GetWritableData(), offset, value);
131 }
132 
133 void WriteUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint8_t value)
134 {
135  BOOST_ASSERT(packetBuffer);
136 
137  WriteUint8(packetBuffer->GetWritableData(), offset, value);
138 }
139 
140 void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize)
141 {
142  BOOST_ASSERT(buffer);
143  BOOST_ASSERT(value);
144 
145  for (unsigned int i = 0; i < valueSize; i++, offset++)
146  {
147  buffer[offset] = *(reinterpret_cast<const unsigned char*>(value) + i);
148  }
149 }
150 
151 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
152 {
153  BOOST_ASSERT(buffer);
154 
155  buffer[offset] = static_cast<unsigned char>(value & 0xFF);
156  buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
157  buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
158  buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
159  buffer[offset + 4] = static_cast<unsigned char>((value >> 32) & 0xFF);
160  buffer[offset + 5] = static_cast<unsigned char>((value >> 40) & 0xFF);
161  buffer[offset + 6] = static_cast<unsigned char>((value >> 48) & 0xFF);
162  buffer[offset + 7] = static_cast<unsigned char>((value >> 56) & 0xFF);
163 }
164 
165 void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value)
166 {
167  BOOST_ASSERT(buffer);
168 
169  buffer[offset] = static_cast<unsigned char>(value & 0xFF);
170  buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
171  buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
172  buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
173 }
174 
175 void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value)
176 {
177  BOOST_ASSERT(buffer);
178 
179  buffer[offset] = static_cast<unsigned char>(value & 0xFF);
180  buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
181 }
182 
183 void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value)
184 {
185  BOOST_ASSERT(buffer);
186 
187  buffer[offset] = static_cast<unsigned char>(value);
188 }
189 
190 void ReadBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
191 {
192  BOOST_ASSERT(packetBuffer);
193 
194  ReadBytes(packetBuffer->GetReadableData(), offset, valueSize, outValue);
195 }
196 
197 uint64_t ReadUint64(const IPacketBufferPtr& packetBuffer, unsigned int offset)
198 {
199  BOOST_ASSERT(packetBuffer);
200 
201  return ReadUint64(packetBuffer->GetReadableData(), offset);
202 }
203 
204 uint32_t ReadUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset)
205 {
206  BOOST_ASSERT(packetBuffer);
207 
208  return ReadUint32(packetBuffer->GetReadableData(), offset);
209 }
210 
211 uint16_t ReadUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset)
212 {
213  BOOST_ASSERT(packetBuffer);
214 
215  return ReadUint16(packetBuffer->GetReadableData(), offset);
216 }
217 
218 uint8_t ReadUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset)
219 {
220  BOOST_ASSERT(packetBuffer);
221 
222  return ReadUint8(packetBuffer->GetReadableData(), offset);
223 }
224 
225 void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
226 {
227  BOOST_ASSERT(buffer);
228  BOOST_ASSERT(outValue);
229 
230  for (unsigned int i = 0; i < valueSize; i++, offset++)
231  {
232  outValue[i] = static_cast<uint8_t>(buffer[offset]);
233  }
234 }
235 
236 uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
237 {
238  BOOST_ASSERT(buffer);
239 
240  uint64_t value = 0;
241  value = static_cast<uint64_t>(buffer[offset]);
242  value |= static_cast<uint64_t>(buffer[offset + 1]) << 8;
243  value |= static_cast<uint64_t>(buffer[offset + 2]) << 16;
244  value |= static_cast<uint64_t>(buffer[offset + 3]) << 24;
245  value |= static_cast<uint64_t>(buffer[offset + 4]) << 32;
246  value |= static_cast<uint64_t>(buffer[offset + 5]) << 40;
247  value |= static_cast<uint64_t>(buffer[offset + 6]) << 48;
248  value |= static_cast<uint64_t>(buffer[offset + 7]) << 56;
249 
250  return value;
251 }
252 
253 uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset)
254 {
255  BOOST_ASSERT(buffer);
256 
257  uint32_t value = 0;
258  value = static_cast<uint32_t>(buffer[offset]);
259  value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
260  value |= static_cast<uint32_t>(buffer[offset + 2]) << 16;
261  value |= static_cast<uint32_t>(buffer[offset + 3]) << 24;
262  return value;
263 }
264 
265 uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset)
266 {
267  BOOST_ASSERT(buffer);
268 
269  uint32_t value = 0;
270  value = static_cast<uint32_t>(buffer[offset]);
271  value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
272  return static_cast<uint16_t>(value);
273 }
274 
275 uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset)
276 {
277  BOOST_ASSERT(buffer);
278 
279  return buffer[offset];
280 }
281 
282 std::string GetSoftwareInfo()
283 {
284  return std::string("ArmNN");
285 }
286 
287 std::string GetHardwareVersion()
288 {
289  return std::string();
290 }
291 
292 std::string GetSoftwareVersion()
293 {
294  std::string armnnVersion(ARMNN_VERSION);
295  std::string result = "Armnn " + armnnVersion.substr(2,2) + "." + armnnVersion.substr(4,2);
296  return result;
297 }
298 
299 std::string GetProcessName()
300 {
301  std::ifstream comm("/proc/self/comm");
302  std::string name;
303  getline(comm, name);
304  return name;
305 }
306 
307 // Calculate the actual length an SwString will be including the terminating null character
308 // padding to bring it to the next uint32_t boundary but minus the leading uint32_t encoding
309 // the size to allow the offset to be correctly updated when decoding a binary packet.
310 uint32_t CalculateSizeOfPaddedSwString(const std::string& str)
311 {
312  std::vector<uint32_t> swTraceString;
313  StringToSwTraceString<SwTraceCharPolicy>(str, swTraceString);
314  unsigned int uint32_t_size = sizeof(uint32_t);
315  uint32_t size = (boost::numeric_cast<uint32_t>(swTraceString.size()) - 1) * uint32_t_size;
316  return size;
317 }
318 
319 // Read TimelineMessageDirectoryPacket from given IPacketBuffer and offset
320 SwTraceMessage ReadSwTraceMessage(const unsigned char* packetBuffer, unsigned int& offset)
321 {
322  BOOST_ASSERT(packetBuffer);
323 
324  unsigned int uint32_t_size = sizeof(uint32_t);
325 
326  SwTraceMessage swTraceMessage;
327 
328  // Read the decl_id
329  uint32_t readDeclId = ReadUint32(packetBuffer, offset);
330  swTraceMessage.m_Id = readDeclId;
331 
332  // SWTrace "namestring" format
333  // length of the string (first 4 bytes) + string + null terminator
334 
335  // Check the decl_name
336  offset += uint32_t_size;
337  uint32_t swTraceDeclNameLength = ReadUint32(packetBuffer, offset);
338 
339  offset += uint32_t_size;
340  std::vector<unsigned char> swTraceStringBuffer(swTraceDeclNameLength - 1);
341  std::memcpy(swTraceStringBuffer.data(),
342  packetBuffer + offset, swTraceStringBuffer.size());
343 
344  swTraceMessage.m_Name.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // name
345 
346  // Check the ui_name
347  offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_Name);
348  uint32_t swTraceUINameLength = ReadUint32(packetBuffer, offset);
349 
350  offset += uint32_t_size;
351  swTraceStringBuffer.resize(swTraceUINameLength - 1);
352  std::memcpy(swTraceStringBuffer.data(),
353  packetBuffer + offset, swTraceStringBuffer.size());
354 
355  swTraceMessage.m_UiName.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // ui_name
356 
357  // Check arg_types
358  offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_UiName);
359  uint32_t swTraceArgTypesLength = ReadUint32(packetBuffer, offset);
360 
361  offset += uint32_t_size;
362  swTraceStringBuffer.resize(swTraceArgTypesLength - 1);
363  std::memcpy(swTraceStringBuffer.data(),
364  packetBuffer + offset, swTraceStringBuffer.size());
365 
366  swTraceMessage.m_ArgTypes.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // arg_types
367 
368  std::string swTraceString(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
369 
370  // Check arg_names
371  offset += CalculateSizeOfPaddedSwString(swTraceString);
372  uint32_t swTraceArgNamesLength = ReadUint32(packetBuffer, offset);
373 
374  offset += uint32_t_size;
375  swTraceStringBuffer.resize(swTraceArgNamesLength - 1);
376  std::memcpy(swTraceStringBuffer.data(),
377  packetBuffer + offset, swTraceStringBuffer.size());
378 
379  swTraceString.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
380  std::stringstream stringStream(swTraceString);
381  std::string argName;
382  while (std::getline(stringStream, argName, ','))
383  {
384  swTraceMessage.m_ArgNames.push_back(argName);
385  }
386 
387  offset += CalculateSizeOfPaddedSwString(swTraceString);
388 
389  return swTraceMessage;
390 }
391 
404 std::pair<uint32_t, uint32_t> CreateTimelinePacketHeader(uint32_t packetFamily,
405  uint32_t packetClass,
406  uint32_t packetType,
407  uint32_t streamId,
408  uint32_t sequenceNumbered,
409  uint32_t dataLength)
410 {
411  // Packet header word 0:
412  // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
413  // 19:25 [7] packet_class: packet class
414  // 16:18 [3] packet_type: packet type
415  // 8:15 [8] reserved: all zeros
416  // 0:7 [8] stream_id: stream identifier
417  uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
418  ((packetClass & 0x0000007F) << 19) |
419  ((packetType & 0x00000007) << 16) |
420  ((streamId & 0x00000007) << 0);
421 
422  // Packet header word 1:
423  // 25:31 [7] reserved: all zeros
424  // 24 [1] sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
425  // 0:23 [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
426  uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
427  ((dataLength & 0x00FFFFFF) << 0);
428 
429  return std::make_pair(packetHeaderWord0, packetHeaderWord1);
430 }
431 
444 std::pair<uint32_t, uint32_t> CreateTimelineMessagePacketHeader(unsigned int dataLength)
445 {
446  return CreateTimelinePacketHeader(1, // Packet family
447  0, // Packet class
448  1, // Packet type
449  0, // Stream id
450  0, // Sequence number
451  dataLength); // Data length
452 }
453 
455  const std::string& label,
456  unsigned char* buffer,
457  unsigned int bufferSize,
458  unsigned int& numberOfBytesWritten)
459 {
460  // Initialize the output value
461  numberOfBytesWritten = 0;
462 
463  // Check that the given buffer is valid
464  if (buffer == nullptr || bufferSize == 0)
465  {
467  }
468 
469  // Utils
470  unsigned int uint32_t_size = sizeof(uint32_t);
471  unsigned int uint64_t_size = sizeof(uint64_t);
472 
473  // Convert the label into a SWTrace string
474  std::vector<uint32_t> swTraceLabel;
475  bool result = StringToSwTraceString<SwTraceCharPolicy>(label, swTraceLabel);
476  if (!result)
477  {
479  }
480 
481  // Calculate the size of the SWTrace string label (in bytes)
482  unsigned int swTraceLabelSize = boost::numeric_cast<unsigned int>(swTraceLabel.size()) * uint32_t_size;
483 
484  // Calculate the length of the data (in bytes)
485  unsigned int timelineLabelPacketDataLength = uint32_t_size + // decl_Id
486  uint64_t_size + // Profiling GUID
487  swTraceLabelSize; // Label
488 
489  // Calculate the timeline binary packet size (in bytes)
490  unsigned int timelineLabelPacketSize = 2 * uint32_t_size + // Header (2 words)
491  timelineLabelPacketDataLength; // decl_Id + Profiling GUID + label
492 
493  // Check whether the timeline binary packet fits in the given buffer
494  if (timelineLabelPacketSize > bufferSize)
495  {
497  }
498 
499  // Create packet header
500  std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineLabelPacketDataLength);
501 
502  // Initialize the offset for writing in the buffer
503  unsigned int offset = 0;
504 
505  // Write the timeline binary packet header to the buffer
506  WriteUint32(buffer, offset, packetHeader.first);
507  offset += uint32_t_size;
508  WriteUint32(buffer, offset, packetHeader.second);
509  offset += uint32_t_size;
510 
511  // Write decl_Id to the buffer
512  WriteUint32(buffer, offset, 0u);
513  offset += uint32_t_size;
514 
515  // Write the timeline binary packet payload to the buffer
516  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
517  offset += uint64_t_size;
518  for (uint32_t swTraceLabelWord : swTraceLabel)
519  {
520  WriteUint32(buffer, offset, swTraceLabelWord); // Label
521  offset += uint32_t_size;
522  }
523 
524  // Update the number of bytes written
525  numberOfBytesWritten = timelineLabelPacketSize;
526 
528 }
529 
531  unsigned char* buffer,
532  unsigned int bufferSize,
533  unsigned int& numberOfBytesWritten)
534 {
535  // Initialize the output value
536  numberOfBytesWritten = 0;
537 
538  // Check that the given buffer is valid
539  if (buffer == nullptr || bufferSize == 0)
540  {
542  }
543 
544  // Utils
545  unsigned int uint32_t_size = sizeof(uint32_t);
546  unsigned int uint64_t_size = sizeof(uint64_t);
547 
548  // Calculate the length of the data (in bytes)
549  unsigned int timelineEntityPacketDataLength = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
550 
551 
552  // Calculate the timeline binary packet size (in bytes)
553  unsigned int timelineEntityPacketSize = 2 * uint32_t_size + // Header (2 words)
554  timelineEntityPacketDataLength; // Profiling GUID
555 
556  // Check whether the timeline binary packet fits in the given buffer
557  if (timelineEntityPacketSize > bufferSize)
558  {
560  }
561 
562  // Create packet header
563  std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEntityPacketDataLength);
564 
565  // Initialize the offset for writing in the buffer
566  unsigned int offset = 0;
567 
568  // Write the timeline binary packet header to the buffer
569  WriteUint32(buffer, offset, packetHeader.first);
570  offset += uint32_t_size;
571  WriteUint32(buffer, offset, packetHeader.second);
572  offset += uint32_t_size;
573 
574  // Write the decl_Id to the buffer
575  WriteUint32(buffer, offset, 1u);
576  offset += uint32_t_size;
577 
578  // Write the timeline binary packet payload to the buffer
579  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
580 
581  // Update the number of bytes written
582  numberOfBytesWritten = timelineEntityPacketSize;
583 
585 }
586 
588  uint64_t relationshipGuid,
589  uint64_t headGuid,
590  uint64_t tailGuid,
591  unsigned char* buffer,
592  unsigned int bufferSize,
593  unsigned int& numberOfBytesWritten)
594 {
595  // Initialize the output value
596  numberOfBytesWritten = 0;
597 
598  // Check that the given buffer is valid
599  if (buffer == nullptr || bufferSize == 0)
600  {
602  }
603 
604  // Utils
605  unsigned int uint32_t_size = sizeof(uint32_t);
606  unsigned int uint64_t_size = sizeof(uint64_t);
607 
608  // Calculate the length of the data (in bytes)
609  unsigned int timelineRelationshipPacketDataLength = uint32_t_size * 2 + // decl_id + Relationship Type
610  uint64_t_size * 3; // Relationship GUID + Head GUID + tail GUID
611 
612  // Calculate the timeline binary packet size (in bytes)
613  unsigned int timelineRelationshipPacketSize = 2 * uint32_t_size + // Header (2 words)
614  timelineRelationshipPacketDataLength;
615 
616  // Check whether the timeline binary packet fits in the given buffer
617  if (timelineRelationshipPacketSize > bufferSize)
618  {
620  }
621 
622  // Create packet header
623  uint32_t dataLength = boost::numeric_cast<uint32_t>(timelineRelationshipPacketDataLength);
624  std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(dataLength);
625 
626  // Initialize the offset for writing in the buffer
627  unsigned int offset = 0;
628 
629  // Write the timeline binary packet header to the buffer
630  WriteUint32(buffer, offset, packetHeader.first);
631  offset += uint32_t_size;
632  WriteUint32(buffer, offset, packetHeader.second);
633  offset += uint32_t_size;
634 
635  uint32_t relationshipTypeUint = 0;
636 
637  switch (relationshipType)
638  {
640  relationshipTypeUint = 0;
641  break;
643  relationshipTypeUint = 1;
644  break;
646  relationshipTypeUint = 2;
647  break;
649  relationshipTypeUint = 3;
650  break;
651  default:
652  throw InvalidArgumentException("Unknown relationship type given.");
653  }
654 
655  // Write the timeline binary packet payload to the buffer
656  // decl_id of the timeline message
657  uint32_t declId = 3;
658  WriteUint32(buffer, offset, declId); // decl_id
659  offset += uint32_t_size;
660  WriteUint32(buffer, offset, relationshipTypeUint); // Relationship Type
661  offset += uint32_t_size;
662  WriteUint64(buffer, offset, relationshipGuid); // GUID of this relationship
663  offset += uint64_t_size;
664  WriteUint64(buffer, offset, headGuid); // head of relationship GUID
665  offset += uint64_t_size;
666  WriteUint64(buffer, offset, tailGuid); // tail of relationship GUID
667 
668  // Update the number of bytes written
669  numberOfBytesWritten = timelineRelationshipPacketSize;
670 
672 }
673 
675  unsigned int bufferSize,
676  unsigned int& numberOfBytesWritten)
677 {
678  // Initialize the output value
679  numberOfBytesWritten = 0;
680 
681  // Check that the given buffer is valid
682  if (buffer == nullptr || bufferSize == 0)
683  {
685  }
686 
687  // Utils
688  unsigned int uint8_t_size = sizeof(uint8_t);
689  unsigned int uint32_t_size = sizeof(uint32_t);
690  unsigned int uint64_t_size = sizeof(uint64_t);
691  unsigned int threadId_size = sizeof(std::thread::id);
692 
693  // The payload/data of the packet consists of swtrace event definitions encoded according
694  // to the swtrace directory specification. The messages being the five defined below:
695  //
696  // | decl_id | decl_name | ui_name | arg_types | arg_names |
697  // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
698  // | 0 | declareLabel | declare label | ps | guid,value |
699  // | 1 | declareEntity | declare entity | p | guid |
700  // | 2 | declareEventClass | declare event class | p | guid |
701  // | 3 | declareRelationship | declare relationship | Ippp | relationshipType,relationshipGuid, |
702  // | | | | | headGuid,tailGuid |
703  // | 4 | declareEvent | declare event | @tp | timestamp,threadId,eventGuid |
704  std::vector<std::vector<std::string>> timelineDirectoryMessages
705  {
706  { "0", "declareLabel", "declare label", "ps", "guid,value" },
707  { "1", "declareEntity", "declare entity", "p", "guid" },
708  { "2", "declareEventClass", "declare event class", "p", "guid" },
709  { "3", "declareRelationship", "declare relationship", "Ippp",
710  "relationshipType,relationshipGuid,headGuid,tailGuid" },
711  { "4", "declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid" }
712  };
713 
714  // Build the message declarations
715  std::vector<uint32_t> swTraceBuffer;
716  for (const auto& directoryComponent : timelineDirectoryMessages)
717  {
718  // decl_id
719  uint32_t declId = 0;
720  try
721  {
722  declId = boost::numeric_cast<uint32_t>(std::stoul(directoryComponent[0]));
723  }
724  catch (const std::exception&)
725  {
727  }
728  swTraceBuffer.push_back(declId);
729 
730  bool result = true;
731  result &= ConvertDirectoryComponent<SwTraceNameCharPolicy>(directoryComponent[1], swTraceBuffer); // decl_name
732  result &= ConvertDirectoryComponent<SwTraceCharPolicy> (directoryComponent[2], swTraceBuffer); // ui_name
733  result &= ConvertDirectoryComponent<SwTraceTypeCharPolicy>(directoryComponent[3], swTraceBuffer); // arg_types
734  result &= ConvertDirectoryComponent<SwTraceCharPolicy> (directoryComponent[4], swTraceBuffer); // arg_names
735  if (!result)
736  {
738  }
739  }
740 
741  unsigned int dataLength = 3 * uint8_t_size + // Stream header (3 bytes)
742  boost::numeric_cast<unsigned int>(swTraceBuffer.size()) *
743  uint32_t_size; // Trace directory (5 messages)
744 
745  // Calculate the timeline directory binary packet size (in bytes)
746  unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
747  dataLength; // Payload
748 
749  // Check whether the timeline directory binary packet fits in the given buffer
750  if (timelineDirectoryPacketSize > bufferSize)
751  {
753  }
754 
755  // Create packet header
756  auto packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, boost::numeric_cast<uint32_t>(dataLength));
757 
758  // Initialize the offset for writing in the buffer
759  unsigned int offset = 0;
760 
761  // Write the timeline binary packet header to the buffer
762  WriteUint32(buffer, offset, packetHeader.first);
763  offset += uint32_t_size;
764  WriteUint32(buffer, offset, packetHeader.second);
765  offset += uint32_t_size;
766 
767  // Write the stream header
768  uint8_t streamVersion = 4;
769  uint8_t pointerBytes = boost::numeric_cast<uint8_t>(uint64_t_size); // All GUIDs are uint64_t
770  uint8_t threadIdBytes = boost::numeric_cast<uint8_t>(threadId_size);
771  switch (threadIdBytes)
772  {
773  case 4: // Typically Windows and Android
774  case 8: // Typically Linux
775  break; // Valid values
776  default:
777  return TimelinePacketStatus::Error; // Invalid value
778  }
779  WriteUint8(buffer, offset, streamVersion);
780  offset += uint8_t_size;
781  WriteUint8(buffer, offset, pointerBytes);
782  offset += uint8_t_size;
783  WriteUint8(buffer, offset, threadIdBytes);
784  offset += uint8_t_size;
785 
786  // Write the SWTrace directory
787  uint32_t numberOfDeclarations = boost::numeric_cast<uint32_t>(timelineDirectoryMessages.size());
788  WriteUint32(buffer, offset, numberOfDeclarations); // Number of declarations
789  offset += uint32_t_size;
790  for (uint32_t i : swTraceBuffer)
791  {
792  WriteUint32(buffer, offset, i); // Message declarations
793  offset += uint32_t_size;
794  }
795 
796  // Update the number of bytes written
797  numberOfBytesWritten = timelineDirectoryPacketSize;
798 
800 }
801 
803  unsigned char* buffer,
804  unsigned int bufferSize,
805  unsigned int& numberOfBytesWritten)
806 {
807  // Initialize the output value
808  numberOfBytesWritten = 0;
809 
810  // Check that the given buffer is valid
811  if (buffer == nullptr || bufferSize == 0)
812  {
814  }
815 
816  // Utils
817  unsigned int uint32_t_size = sizeof(uint32_t);
818  unsigned int uint64_t_size = sizeof(uint64_t);
819 
820  // decl_id of the timeline message
821  uint32_t declId = 2;
822 
823  // Calculate the length of the data (in bytes)
824  unsigned int packetBodySize = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
825 
826  // Calculate the timeline binary packet size (in bytes)
827  unsigned int packetSize = 2 * uint32_t_size + // Header (2 words)
828  packetBodySize; // Body
829 
830  // Check whether the timeline binary packet fits in the given buffer
831  if (packetSize > bufferSize)
832  {
834  }
835 
836  // Create packet header
837  std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(packetBodySize);
838 
839  // Initialize the offset for writing in the buffer
840  unsigned int offset = 0;
841 
842  // Write the timeline binary packet header to the buffer
843  WriteUint32(buffer, offset, packetHeader.first);
844  offset += uint32_t_size;
845  WriteUint32(buffer, offset, packetHeader.second);
846  offset += uint32_t_size;
847 
848  // Write the timeline binary packet payload to the buffer
849  WriteUint32(buffer, offset, declId); // decl_id
850  offset += uint32_t_size;
851  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
852 
853  // Update the number of bytes written
854  numberOfBytesWritten = packetSize;
855 
857 }
858 
860  std::thread::id threadId,
861  uint64_t profilingGuid,
862  unsigned char* buffer,
863  unsigned int bufferSize,
864  unsigned int& numberOfBytesWritten)
865 {
866  // Initialize the output value
867  numberOfBytesWritten = 0;
868 
869  // Check that the given buffer is valid
870  if (buffer == nullptr || bufferSize == 0)
871  {
873  }
874 
875  // Utils
876  unsigned int uint32_t_size = sizeof(uint32_t);
877  unsigned int uint64_t_size = sizeof(uint64_t);
878  unsigned int threadId_size = sizeof(std::thread::id);
879 
880  // decl_id of the timeline message
881  uint32_t declId = 4;
882 
883  // Calculate the length of the data (in bytes)
884  unsigned int timelineEventPacketDataLength = uint32_t_size + // decl_id
885  uint64_t_size + // Timestamp
886  threadId_size + // Thread id
887  uint64_t_size; // Profiling GUID
888 
889  // Calculate the timeline binary packet size (in bytes)
890  unsigned int timelineEventPacketSize = 2 * uint32_t_size + // Header (2 words)
891  timelineEventPacketDataLength; // Timestamp + thread id + profiling GUID
892 
893  // Check whether the timeline binary packet fits in the given buffer
894  if (timelineEventPacketSize > bufferSize)
895  {
897  }
898 
899  // Create packet header
900  std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEventPacketDataLength);
901 
902  // Initialize the offset for writing in the buffer
903  unsigned int offset = 0;
904 
905  // Write the timeline binary packet header to the buffer
906  WriteUint32(buffer, offset, packetHeader.first);
907  offset += uint32_t_size;
908  WriteUint32(buffer, offset, packetHeader.second);
909  offset += uint32_t_size;
910 
911  // Write the timeline binary packet payload to the buffer
912  WriteUint32(buffer, offset, declId); // decl_id
913  offset += uint32_t_size;
914  WriteUint64(buffer, offset, timestamp); // Timestamp
915  offset += uint64_t_size;
916  WriteBytes(buffer, offset, &threadId, threadId_size); // Thread id
917  offset += threadId_size;
918  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
919  offset += uint64_t_size;
920 
921  // Update the number of bytes written
922  numberOfBytesWritten = timelineEventPacketSize;
923 
925 }
926 
927 std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
928 {
929  std::stringstream outputStream, centrePadding;
930  int padding = spacingWidth - static_cast<int>(stringToPass.size());
931 
932  for (int i = 0; i < padding / 2; ++i)
933  {
934  centrePadding << " ";
935  }
936 
937  outputStream << centrePadding.str() << stringToPass << centrePadding.str();
938 
939  if (padding > 0 && padding %2 != 0)
940  {
941  outputStream << " ";
942  }
943 
944  return outputStream.str();
945 }
946 
947 void PrintDeviceDetails(const std::pair<const unsigned short, std::unique_ptr<Device>>& devicePair)
948 {
949  std::string body;
950 
951  body.append(CentreAlignFormatting(devicePair.second->m_Name, 20));
952  body.append(" | ");
953  body.append(CentreAlignFormatting(std::to_string(devicePair.first), 13));
954  body.append(" | ");
955  body.append(CentreAlignFormatting(std::to_string(devicePair.second->m_Cores), 10));
956  body.append("\n");
957 
958  std::cout << std::string(body.size(), '-') << "\n";
959  std::cout<< body;
960 }
961 
962 void PrintCounterSetDetails(const std::pair<const unsigned short, std::unique_ptr<CounterSet>>& counterSetPair)
963 {
964  std::string body;
965 
966  body.append(CentreAlignFormatting(counterSetPair.second->m_Name, 20));
967  body.append(" | ");
968  body.append(CentreAlignFormatting(std::to_string(counterSetPair.first), 13));
969  body.append(" | ");
970  body.append(CentreAlignFormatting(std::to_string(counterSetPair.second->m_Count), 10));
971  body.append("\n");
972 
973  std::cout << std::string(body.size(), '-') << "\n";
974 
975  std::cout<< body;
976 }
977 
978 void PrintCounterDetails(std::shared_ptr<Counter>& counter)
979 {
980  std::string body;
981 
982  body.append(CentreAlignFormatting(counter->m_Name, 20));
983  body.append(" | ");
984  body.append(CentreAlignFormatting(counter->m_Description, 50));
985  body.append(" | ");
986  body.append(CentreAlignFormatting(counter->m_Units, 14));
987  body.append(" | ");
988  body.append(CentreAlignFormatting(std::to_string(counter->m_Uid), 6));
989  body.append(" | ");
990  body.append(CentreAlignFormatting(std::to_string(counter->m_MaxCounterUid), 10));
991  body.append(" | ");
992  body.append(CentreAlignFormatting(std::to_string(counter->m_Class), 8));
993  body.append(" | ");
994  body.append(CentreAlignFormatting(std::to_string(counter->m_Interpolation), 14));
995  body.append(" | ");
996  body.append(CentreAlignFormatting(std::to_string(counter->m_Multiplier), 20));
997  body.append(" | ");
998  body.append(CentreAlignFormatting(std::to_string(counter->m_CounterSetUid), 16));
999  body.append(" | ");
1000  body.append(CentreAlignFormatting(std::to_string(counter->m_DeviceUid), 14));
1001 
1002  body.append("\n");
1003 
1004  std::cout << std::string(body.size(), '-') << "\n";
1005 
1006  std::cout << body;
1007 }
1008 
1009 void PrintCategoryDetails(const std::unique_ptr<Category>& category,
1010  std::unordered_map<unsigned short, std::shared_ptr<Counter>> counterMap)
1011 {
1012  std::string categoryBody;
1013  std::string categoryHeader;
1014 
1015  categoryHeader.append(CentreAlignFormatting("Name", 20));
1016  categoryHeader.append(" | ");
1017  categoryHeader.append(CentreAlignFormatting("Device", 12));
1018  categoryHeader.append(" | ");
1019  categoryHeader.append(CentreAlignFormatting("Counter set UID:", 16));
1020  categoryHeader.append(" | ");
1021  categoryHeader.append(CentreAlignFormatting("Event Count", 14));
1022  categoryHeader.append("\n");
1023 
1024  categoryBody.append(CentreAlignFormatting(category->m_Name, 20));
1025  categoryBody.append(" | ");
1026  categoryBody.append(CentreAlignFormatting(std::to_string(category->m_DeviceUid), 12));
1027  categoryBody.append(" | ");
1028  categoryBody.append(CentreAlignFormatting(std::to_string(category->m_CounterSetUid), 16));
1029  categoryBody.append(" | ");
1030  categoryBody.append(CentreAlignFormatting(std::to_string(category->m_Counters.size()), 14));
1031 
1032  std::cout << "\n" << "\n";
1033  std::cout << CentreAlignFormatting("CATEGORY", static_cast<int>(categoryHeader.size()));
1034  std::cout << "\n";
1035  std::cout << std::string(categoryHeader.size(), '=') << "\n";
1036 
1037  std::cout << categoryHeader;
1038 
1039  std::cout << std::string(categoryBody.size(), '-') << "\n";
1040 
1041  std::cout << categoryBody;
1042 
1043  std::string counterHeader;
1044 
1045  counterHeader.append(CentreAlignFormatting("Counter Name", 20));
1046  counterHeader.append(" | ");
1047  counterHeader.append(CentreAlignFormatting("Description", 50));
1048  counterHeader.append(" | ");
1049  counterHeader.append(CentreAlignFormatting("Units", 14));
1050  counterHeader.append(" | ");
1051  counterHeader.append(CentreAlignFormatting("UID", 6));
1052  counterHeader.append(" | ");
1053  counterHeader.append(CentreAlignFormatting("Max UID", 10));
1054  counterHeader.append(" | ");
1055  counterHeader.append(CentreAlignFormatting("Class", 8));
1056  counterHeader.append(" | ");
1057  counterHeader.append(CentreAlignFormatting("Interpolation", 14));
1058  counterHeader.append(" | ");
1059  counterHeader.append(CentreAlignFormatting("Multiplier", 20));
1060  counterHeader.append(" | ");
1061  counterHeader.append(CentreAlignFormatting("Counter set UID", 16));
1062  counterHeader.append(" | ");
1063  counterHeader.append(CentreAlignFormatting("Device UID", 14));
1064  counterHeader.append("\n");
1065 
1066  std::cout << "\n" << "\n";
1067  std::cout << CentreAlignFormatting("EVENTS IN CATEGORY: " + category->m_Name,
1068  static_cast<int>(counterHeader.size()));
1069  std::cout << "\n";
1070  std::cout << std::string(counterHeader.size(), '=') << "\n";
1071  std::cout << counterHeader;
1072  for (auto& it: category->m_Counters) {
1073  auto search = counterMap.find(it);
1074  if(search != counterMap.end()) {
1075  PrintCounterDetails(search->second);
1076  }
1077  }
1078 }
1079 
1081 {
1082  std::string devicesHeader;
1083 
1084  devicesHeader.append(CentreAlignFormatting("Device name", 20));
1085  devicesHeader.append(" | ");
1086  devicesHeader.append(CentreAlignFormatting("UID", 13));
1087  devicesHeader.append(" | ");
1088  devicesHeader.append(CentreAlignFormatting("Cores", 10));
1089  devicesHeader.append("\n");
1090 
1091  std::cout << "\n" << "\n";
1092  std::cout << CentreAlignFormatting("DEVICES", static_cast<int>(devicesHeader.size()));
1093  std::cout << "\n";
1094  std::cout << std::string(devicesHeader.size(), '=') << "\n";
1095  std::cout << devicesHeader;
1096  for (auto& it: counterDirectory.GetDevices()) {
1097  PrintDeviceDetails(it);
1098  }
1099 
1100  std::string counterSetHeader;
1101 
1102  counterSetHeader.append(CentreAlignFormatting("Counter set name", 20));
1103  counterSetHeader.append(" | ");
1104  counterSetHeader.append(CentreAlignFormatting("UID", 13));
1105  counterSetHeader.append(" | ");
1106  counterSetHeader.append(CentreAlignFormatting("Count", 10));
1107  counterSetHeader.append("\n");
1108 
1109  std::cout << "\n" << "\n";
1110  std::cout << CentreAlignFormatting("COUNTER SETS", static_cast<int>(counterSetHeader.size()));
1111  std::cout << "\n";
1112  std::cout << std::string(counterSetHeader.size(), '=') << "\n";
1113 
1114  std::cout << counterSetHeader;
1115 
1116  for (auto& it: counterDirectory.GetCounterSets()) {
1118  }
1119 
1120  auto counters = counterDirectory.GetCounters();
1121  for (auto& it: counterDirectory.GetCategories()) {
1122  PrintCategoryDetails(it, counters);
1123  }
1124  std::cout << "\n";
1125 }
1126 
1127 uint64_t GetTimestamp()
1128 {
1129 #if USE_CLOCK_MONOTONIC_RAW
1130  using clock = MonotonicClockRaw;
1131 #else
1132  using clock = std::chrono::steady_clock;
1133 #endif
1134 
1135  // Take a timestamp
1136  auto timestamp = clock::now();
1137 
1138  return static_cast<uint64_t>(timestamp.time_since_epoch().count());
1139 }
1140 
1141 } // namespace profiling
1142 
1143 } // namespace armnn
1144 
1145 namespace std
1146 {
1147 
1148 bool operator==(const std::vector<uint8_t>& left, std::thread::id right)
1149 {
1150  return std::memcmp(left.data(), &right, left.size()) == 0;
1151 }
1152 
1153 } // namespace std
virtual const Devices & GetDevices() const =0
std::string CentreAlignFormatting(const std::string &stringToPass, const int spacingWidth)
void PrintCounterDirectory(ICounterDirectory &counterDirectory)
uint64_t ReadUint64(const IPacketBufferPtr &packetBuffer, unsigned int offset)
std::string GetSoftwareVersion()
TimelinePacketStatus WriteTimelineEventClassBinaryPacket(uint64_t profilingGuid, unsigned char *buffer, unsigned int bufferSize, unsigned int &numberOfBytesWritten)
void WriteUint64(const std::unique_ptr< IPacketBuffer > &packetBuffer, unsigned int offset, uint64_t value)
uint16_t GetNextUid(bool peekOnly)
void WriteUint16(const IPacketBufferPtr &packetBuffer, unsigned int offset, uint16_t value)
uint16_t ReadUint16(const IPacketBufferPtr &packetBuffer, unsigned int offset)
std::vector< std::string > m_ArgNames
virtual const Categories & GetCategories() const =0
std::unique_ptr< IPacketBuffer > IPacketBufferPtr
std::string GetSoftwareInfo()
TimelinePacketStatus WriteTimelineEntityBinaryPacket(uint64_t profilingGuid, unsigned char *buffer, unsigned int bufferSize, unsigned int &numberOfBytesWritten)
void PrintDeviceDetails(const std::pair< const unsigned short, std::unique_ptr< Device >> &devicePair)
std::string GetProcessName()
virtual const CounterSets & GetCounterSets() const =0
std::string GetHardwareVersion()
std::vector< uint16_t > GetNextCounterUids(uint16_t firstUid, uint16_t cores)
void PrintCounterSetDetails(const std::pair< const unsigned short, std::unique_ptr< CounterSet >> &counterSetPair)
void WriteUint8(const IPacketBufferPtr &packetBuffer, unsigned int offset, uint8_t value)
bool operator==(const std::vector< uint8_t > &left, std::thread::id right)
#define ARMNN_VERSION
Definition: Version.hpp:24
TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid, const std::string &label, unsigned char *buffer, unsigned int bufferSize, unsigned int &numberOfBytesWritten)
void WriteBytes(const IPacketBufferPtr &packetBuffer, unsigned int offset, const void *value, unsigned int valueSize)
void PrintCounterDetails(std::shared_ptr< Counter > &counter)
TimelinePacketStatus WriteTimelineRelationshipBinaryPacket(ProfilingRelationshipType relationshipType, uint64_t relationshipGuid, uint64_t headGuid, uint64_t tailGuid, unsigned char *buffer, unsigned int bufferSize, unsigned int &numberOfBytesWritten)
virtual const Counters & GetCounters() const =0
Head execution start depends on Tail execution completion.
uint32_t ReadUint32(const IPacketBufferPtr &packetBuffer, unsigned int offset)
TimelinePacketStatus WriteTimelineEventBinaryPacket(uint64_t timestamp, std::thread::id threadId, uint64_t profilingGuid, unsigned char *buffer, unsigned int bufferSize, unsigned int &numberOfBytesWritten)
void ReadBytes(const IPacketBufferPtr &packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
void PrintCategoryDetails(const std::unique_ptr< Category > &category, std::unordered_map< unsigned short, std::shared_ptr< Counter >> counterMap)
uint32_t ConstructHeader(uint32_t packetFamily, uint32_t packetId)
std::pair< uint32_t, uint32_t > CreateTimelineMessagePacketHeader(unsigned int dataLength)
uint8_t ReadUint8(const IPacketBufferPtr &packetBuffer, unsigned int offset)
TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char *buffer, unsigned int bufferSize, unsigned int &numberOfBytesWritten)
SwTraceMessage ReadSwTraceMessage(const unsigned char *packetBuffer, unsigned int &offset)
std::pair< uint32_t, uint32_t > CreateTimelinePacketHeader(uint32_t packetFamily, uint32_t packetClass, uint32_t packetType, uint32_t streamId, uint32_t sequenceNumbered, uint32_t dataLength)
void WriteUint32(const IPacketBufferPtr &packetBuffer, unsigned int offset, uint32_t value)
uint32_t CalculateSizeOfPaddedSwString(const std::string &str)