ArmNN
 21.02
ProfilingUtils.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "ProfilingUtils.hpp"
7 
8 #include <common/include/CommonProfilingUtils.hpp>
9 #include <common/include/ProfilingException.hpp>
10 #include <common/include/SwTrace.hpp>
11 
12 #include <armnn/Version.hpp>
13 
14 #include <WallClockTimer.hpp>
15 
16 #include <armnn/utility/Assert.hpp>
17 
18 #include <fstream>
19 #include <iostream>
20 #include <limits>
21 
22 namespace armnn
23 {
24 
25 namespace profiling
26 {
27 
28 namespace
29 {
30 
31 void ThrowIfCantGenerateNextUid(uint16_t uid, uint16_t cores = 0)
32 {
33  // Check that it is possible to generate the next UID without causing an overflow
34  switch (cores)
35  {
36  case 0:
37  case 1:
38  // Number of cores not specified or set to 1 (a value of zero indicates the device is not capable of
39  // running multiple parallel workloads and will not provide multiple streams of data for each event)
40  if (uid == std::numeric_limits<uint16_t>::max())
41  {
42  throw RuntimeException("Generating the next UID for profiling would result in an overflow");
43  }
44  break;
45  default: // cores > 1
46  // Multiple cores available, as max_counter_uid has to be set to: counter_uid + cores - 1, the maximum
47  // allowed value for a counter UID is consequently: uint16_t_max - cores + 1
48  if (uid >= std::numeric_limits<uint16_t>::max() - cores + 1)
49  {
50  throw RuntimeException("Generating the next UID for profiling would result in an overflow");
51  }
52  break;
53  }
54 }
55 
56 } // Anonymous namespace
57 
58 uint16_t GetNextUid(bool peekOnly)
59 {
60  // The UID used for profiling objects and events. The first valid UID is 1, as 0 is a reserved value
61  static uint16_t uid = 1;
62 
63  // Check that it is possible to generate the next UID without causing an overflow (throws in case of error)
64  ThrowIfCantGenerateNextUid(uid);
65 
66  if (peekOnly)
67  {
68  // Peek only
69  return uid;
70  }
71  else
72  {
73  // Get the next UID
74  return uid++;
75  }
76 }
77 
78 std::vector<uint16_t> GetNextCounterUids(uint16_t firstUid, uint16_t cores)
79 {
80  // Check that it is possible to generate the next counter UID without causing an overflow (throws in case of error)
81  ThrowIfCantGenerateNextUid(firstUid, cores);
82 
83  // Get the next counter UIDs
84  size_t counterUidsSize = cores == 0 ? 1 : cores;
85  std::vector<uint16_t> counterUids(counterUidsSize, 0);
86  for (size_t i = 0; i < counterUidsSize; i++)
87  {
88  counterUids[i] = firstUid++;
89  }
90  return counterUids;
91 }
92 
93 void WriteBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, const void* value, unsigned int valueSize)
94 {
95  ARMNN_ASSERT(packetBuffer);
96 
97  WriteBytes(packetBuffer->GetWritableData(), offset, value, valueSize);
98 }
99 
100 uint32_t ConstructHeader(uint32_t packetFamily,
101  uint32_t packetId)
102 {
103  return (( packetFamily & 0x0000003F ) << 26 )|
104  (( packetId & 0x000003FF ) << 16 );
105 }
106 
107 uint32_t ConstructHeader(uint32_t packetFamily, uint32_t packetClass, uint32_t packetType)
108 {
109  return ((packetFamily & 0x0000003F) << 26) |
110  ((packetClass & 0x0000007F) << 19) |
111  ((packetType & 0x00000007) << 16);
112 }
113 
114 void WriteUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint64_t value)
115 {
116  ARMNN_ASSERT(packetBuffer);
117 
118  WriteUint64(packetBuffer->GetWritableData(), offset, value);
119 }
120 
121 void WriteUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint32_t value)
122 {
123  ARMNN_ASSERT(packetBuffer);
124 
125  WriteUint32(packetBuffer->GetWritableData(), offset, value);
126 }
127 
128 void WriteUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint16_t value)
129 {
130  ARMNN_ASSERT(packetBuffer);
131 
132  WriteUint16(packetBuffer->GetWritableData(), offset, value);
133 }
134 
135 void WriteUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint8_t value)
136 {
137  ARMNN_ASSERT(packetBuffer);
138 
139  WriteUint8(packetBuffer->GetWritableData(), offset, value);
140 }
141 
142 void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize)
143 {
144  arm::pipe::WriteBytes(buffer, offset, value, valueSize);
145 }
146 
147 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
148 {
149  arm::pipe::WriteUint64(buffer, offset, value);
150 }
151 
152 void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value)
153 {
154  arm::pipe::WriteUint32(buffer, offset, value);
155 }
156 
157 void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value)
158 {
159  arm::pipe::WriteUint16(buffer, offset, value);
160 }
161 
162 void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value)
163 {
164  arm::pipe::WriteUint8(buffer, offset, value);
165 }
166 
167 void ReadBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
168 {
169  ARMNN_ASSERT(packetBuffer);
170 
171  ReadBytes(packetBuffer->GetReadableData(), offset, valueSize, outValue);
172 }
173 
174 uint64_t ReadUint64(const IPacketBufferPtr& packetBuffer, unsigned int offset)
175 {
176  ARMNN_ASSERT(packetBuffer);
177 
178  return ReadUint64(packetBuffer->GetReadableData(), offset);
179 }
180 
181 uint32_t ReadUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset)
182 {
183  ARMNN_ASSERT(packetBuffer);
184 
185  return ReadUint32(packetBuffer->GetReadableData(), offset);
186 }
187 
188 uint16_t ReadUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset)
189 {
190  ARMNN_ASSERT(packetBuffer);
191 
192  return ReadUint16(packetBuffer->GetReadableData(), offset);
193 }
194 
195 uint8_t ReadUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset)
196 {
197  ARMNN_ASSERT(packetBuffer);
198 
199  return ReadUint8(packetBuffer->GetReadableData(), offset);
200 }
201 
202 void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
203 {
204  arm::pipe::ReadBytes(buffer, offset, valueSize, outValue);
205 }
206 
207 uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
208 {
209  return arm::pipe::ReadUint64(buffer, offset);
210 }
211 
212 uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset)
213 {
214  return arm::pipe::ReadUint32(buffer, offset);
215 }
216 
217 uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset)
218 {
219  return arm::pipe::ReadUint16(buffer, offset);
220 }
221 
222 uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset)
223 {
224  return arm::pipe::ReadUint8(buffer, offset);
225 }
226 
227 std::string GetSoftwareInfo()
228 {
229  return std::string("ArmNN");
230 }
231 
232 std::string GetHardwareVersion()
233 {
234  return std::string();
235 }
236 
237 std::string GetSoftwareVersion()
238 {
239  std::string result = "Armnn " + std::to_string(ARMNN_MAJOR_VERSION) + "." + std::to_string(ARMNN_MINOR_VERSION);
240  return result;
241 }
242 
243 std::string GetProcessName()
244 {
245  std::ifstream comm("/proc/self/comm");
246  std::string name;
247  getline(comm, name);
248  return name;
249 }
250 
251 /// Creates a timeline packet header
252 ///
253 /// \params
254 /// packetFamiliy Timeline Packet Family
255 /// packetClass Timeline Packet Class
256 /// packetType Timeline Packet Type
257 /// streamId Stream identifier
258 /// seqeunceNumbered When non-zero the 4 bytes following the header is a u32 sequence number
259 /// dataLength Unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
260 ///
261 /// \returns
262 /// Pair of uint32_t containing word0 and word1 of the header
263 std::pair<uint32_t, uint32_t> CreateTimelinePacketHeader(uint32_t packetFamily,
264  uint32_t packetClass,
265  uint32_t packetType,
266  uint32_t streamId,
267  uint32_t sequenceNumbered,
268  uint32_t dataLength)
269 {
270  // Packet header word 0:
271  // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
272  // 19:25 [7] packet_class: packet class
273  // 16:18 [3] packet_type: packet type
274  // 8:15 [8] reserved: all zeros
275  // 0:7 [8] stream_id: stream identifier
276  uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
277  ((packetClass & 0x0000007F) << 19) |
278  ((packetType & 0x00000007) << 16) |
279  ((streamId & 0x00000007) << 0);
280 
281  // Packet header word 1:
282  // 25:31 [7] reserved: all zeros
283  // 24 [1] sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
284  // 0:23 [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
285  uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
286  ((dataLength & 0x00FFFFFF) << 0);
287 
288  return std::make_pair(packetHeaderWord0, packetHeaderWord1);
289 }
290 
291 /// Creates a packet header for the timeline messages:
292 /// * declareLabel
293 /// * declareEntity
294 /// * declareEventClass
295 /// * declareRelationship
296 /// * declareEvent
297 ///
298 /// \param
299 /// dataLength The length of the message body in bytes
300 ///
301 /// \returns
302 /// Pair of uint32_t containing word0 and word1 of the header
303 std::pair<uint32_t, uint32_t> CreateTimelineMessagePacketHeader(unsigned int dataLength)
304 {
305  return CreateTimelinePacketHeader(1, // Packet family
306  0, // Packet class
307  1, // Packet type
308  0, // Stream id
309  0, // Sequence number
310  dataLength); // Data length
311 }
312 
314  const std::string& label,
315  unsigned char* buffer,
316  unsigned int remainingBufferSize,
317  unsigned int& numberOfBytesWritten)
318 {
319  // Initialize the output value
320  numberOfBytesWritten = 0;
321 
322  // Check that the given buffer is valid
323  if (buffer == nullptr || remainingBufferSize == 0)
324  {
326  }
327 
328  // Utils
329  unsigned int uint32_t_size = sizeof(uint32_t);
330  unsigned int uint64_t_size = sizeof(uint64_t);
331 
332  // Convert the label into a SWTrace string
333  std::vector<uint32_t> swTraceLabel;
334  bool result = arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>(label, swTraceLabel);
335  if (!result)
336  {
338  }
339 
340  // Calculate the size of the SWTrace string label (in bytes)
341  unsigned int swTraceLabelSize = armnn::numeric_cast<unsigned int>(swTraceLabel.size()) * uint32_t_size;
342 
343  // Calculate the length of the data (in bytes)
344  unsigned int timelineLabelPacketDataLength = uint32_t_size + // decl_Id
345  uint64_t_size + // Profiling GUID
346  swTraceLabelSize; // Label
347 
348  // Check whether the timeline binary packet fits in the given buffer
349  if (timelineLabelPacketDataLength > remainingBufferSize)
350  {
352  }
353 
354  // Initialize the offset for writing in the buffer
355  unsigned int offset = 0;
356 
357  // Write decl_Id to the buffer
358  WriteUint32(buffer, offset, 0u);
359  offset += uint32_t_size;
360 
361  // Write the timeline binary packet payload to the buffer
362  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
363  offset += uint64_t_size;
364  for (uint32_t swTraceLabelWord : swTraceLabel)
365  {
366  WriteUint32(buffer, offset, swTraceLabelWord); // Label
367  offset += uint32_t_size;
368  }
369 
370  // Update the number of bytes written
371  numberOfBytesWritten = timelineLabelPacketDataLength;
372 
374 }
375 
377  unsigned char* buffer,
378  unsigned int remainingBufferSize,
379  unsigned int& numberOfBytesWritten)
380 {
381  // Initialize the output value
382  numberOfBytesWritten = 0;
383 
384  // Check that the given buffer is valid
385  if (buffer == nullptr || remainingBufferSize == 0)
386  {
388  }
389 
390  // Utils
391  unsigned int uint32_t_size = sizeof(uint32_t);
392  unsigned int uint64_t_size = sizeof(uint64_t);
393 
394  // Calculate the length of the data (in bytes)
395  unsigned int timelineEntityDataLength = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
396 
397  // Check whether the timeline binary packet fits in the given buffer
398  if (timelineEntityDataLength > remainingBufferSize)
399  {
401  }
402 
403  // Initialize the offset for writing in the buffer
404  unsigned int offset = 0;
405 
406  // Write the decl_Id to the buffer
407  WriteUint32(buffer, offset, 1u);
408  offset += uint32_t_size;
409 
410  // Write the timeline binary packet payload to the buffer
411  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
412 
413  // Update the number of bytes written
414  numberOfBytesWritten = timelineEntityDataLength;
415 
417 }
418 
420  uint64_t relationshipGuid,
421  uint64_t headGuid,
422  uint64_t tailGuid,
423  uint64_t attributeGuid,
424  unsigned char* buffer,
425  unsigned int remainingBufferSize,
426  unsigned int& numberOfBytesWritten)
427 {
428  // Initialize the output value
429  numberOfBytesWritten = 0;
430 
431  // Check that the given buffer is valid
432  if (buffer == nullptr || remainingBufferSize == 0)
433  {
435  }
436 
437  // Utils
438  unsigned int uint32_t_size = sizeof(uint32_t);
439  unsigned int uint64_t_size = sizeof(uint64_t);
440 
441  // Calculate the length of the data (in bytes)
442  unsigned int timelineRelationshipDataLength = uint32_t_size * 2 + // decl_id + Relationship Type
443  uint64_t_size * 4; // Relationship GUID + Head GUID +
444  // tail GUID + attributeGuid
445 
446  // Check whether the timeline binary fits in the given buffer
447  if (timelineRelationshipDataLength > remainingBufferSize)
448  {
450  }
451 
452  // Initialize the offset for writing in the buffer
453  unsigned int offset = 0;
454 
455  uint32_t relationshipTypeUint = 0;
456 
457  switch (relationshipType)
458  {
460  relationshipTypeUint = 0;
461  break;
463  relationshipTypeUint = 1;
464  break;
466  relationshipTypeUint = 2;
467  break;
469  relationshipTypeUint = 3;
470  break;
471  default:
472  throw InvalidArgumentException("Unknown relationship type given.");
473  }
474 
475  // Write the timeline binary payload to the buffer
476  // decl_id of the timeline message
477  uint32_t declId = 3;
478  WriteUint32(buffer, offset, declId); // decl_id
479  offset += uint32_t_size;
480  WriteUint32(buffer, offset, relationshipTypeUint); // Relationship Type
481  offset += uint32_t_size;
482  WriteUint64(buffer, offset, relationshipGuid); // GUID of this relationship
483  offset += uint64_t_size;
484  WriteUint64(buffer, offset, headGuid); // head of relationship GUID
485  offset += uint64_t_size;
486  WriteUint64(buffer, offset, tailGuid); // tail of relationship GUID
487  offset += uint64_t_size;
488  WriteUint64(buffer, offset, attributeGuid); // attribute of relationship GUID
489 
490 
491  // Update the number of bytes written
492  numberOfBytesWritten = timelineRelationshipDataLength;
493 
495 }
496 
498  unsigned int remainingBufferSize,
499  unsigned int& numberOfBytesWritten)
500 {
501  // Initialize the output value
502  numberOfBytesWritten = 0;
503 
504  // Check that the given buffer is valid
505  if (buffer == nullptr || remainingBufferSize == 0)
506  {
508  }
509 
510  // Utils
511  unsigned int uint8_t_size = sizeof(uint8_t);
512  unsigned int uint32_t_size = sizeof(uint32_t);
513  unsigned int uint64_t_size = sizeof(uint64_t);
514 
515  // The payload/data of the packet consists of swtrace event definitions encoded according
516  // to the swtrace directory specification. The messages being the five defined below:
517  //
518  // | decl_id | decl_name | ui_name | arg_types | arg_names |
519  // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
520  // | 0 | declareLabel | declare label | ps | guid,value |
521  // | 1 | declareEntity | declare entity | p | guid |
522  // | 2 | declareEventClass | declare event class | pp | guid,nameGuid |
523  // | 3 | declareRelationship | declare relationship | Ipppp | relationshipType,relationshipGuid, |
524  // | | | | | headGuid,tailGuid,attributeGuid |
525  // | 4 | declareEvent | declare event | @tp | timestamp,threadId,eventGuid |
526  std::vector<std::vector<std::string>> timelineDirectoryMessages
527  {
528  { "0", "declareLabel", "declare label", "ps", "guid,value" },
529  { "1", "declareEntity", "declare entity", "p", "guid" },
530  { "2", "declareEventClass", "declare event class", "pp", "guid,nameGuid" },
531  { "3", "declareRelationship", "declare relationship", "Ipppp",
532  "relationshipType,relationshipGuid,headGuid,tailGuid,attributeGuid" },
533  { "4", "declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid" }
534  };
535 
536  // Build the message declarations
537  std::vector<uint32_t> swTraceBuffer;
538  for (const auto& directoryComponent : timelineDirectoryMessages)
539  {
540  // decl_id
541  uint32_t declId = 0;
542  try
543  {
544  declId = armnn::numeric_cast<uint32_t>(std::stoul(directoryComponent[0]));
545  }
546  catch (const std::exception&)
547  {
549  }
550  swTraceBuffer.push_back(declId);
551 
552  bool result = true;
553  result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceNameCharPolicy>(
554  directoryComponent[1], swTraceBuffer); // decl_name
555  result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceCharPolicy> (
556  directoryComponent[2], swTraceBuffer); // ui_name
557  result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceTypeCharPolicy>(
558  directoryComponent[3], swTraceBuffer); // arg_types
559  result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceCharPolicy> (
560  directoryComponent[4], swTraceBuffer); // arg_names
561  if (!result)
562  {
564  }
565  }
566 
567  unsigned int dataLength = 3 * uint8_t_size + // Stream header (3 bytes)
568  armnn::numeric_cast<unsigned int>(swTraceBuffer.size()) *
569  uint32_t_size; // Trace directory (5 messages)
570 
571  // Calculate the timeline directory binary packet size (in bytes)
572  unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
573  dataLength; // Payload
574 
575  // Check whether the timeline directory binary packet fits in the given buffer
576  if (timelineDirectoryPacketSize > remainingBufferSize)
577  {
579  }
580 
581  // Create packet header
582  auto packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, armnn::numeric_cast<uint32_t>(dataLength));
583 
584  // Initialize the offset for writing in the buffer
585  unsigned int offset = 0;
586 
587  // Write the timeline binary packet header to the buffer
588  WriteUint32(buffer, offset, packetHeader.first);
589  offset += uint32_t_size;
590  WriteUint32(buffer, offset, packetHeader.second);
591  offset += uint32_t_size;
592 
593  // Write the stream header
594  uint8_t streamVersion = 4;
595  uint8_t pointerBytes = armnn::numeric_cast<uint8_t>(uint64_t_size); // All GUIDs are uint64_t
596  uint8_t threadIdBytes = armnn::numeric_cast<uint8_t>(ThreadIdSize);
597  switch (threadIdBytes)
598  {
599  case 4: // Typically Windows and Android
600  case 8: // Typically Linux
601  break; // Valid values
602  default:
603  return TimelinePacketStatus::Error; // Invalid value
604  }
605  WriteUint8(buffer, offset, streamVersion);
606  offset += uint8_t_size;
607  WriteUint8(buffer, offset, pointerBytes);
608  offset += uint8_t_size;
609  WriteUint8(buffer, offset, threadIdBytes);
610  offset += uint8_t_size;
611 
612  // Write the SWTrace directory
613  uint32_t numberOfDeclarations = armnn::numeric_cast<uint32_t>(timelineDirectoryMessages.size());
614  WriteUint32(buffer, offset, numberOfDeclarations); // Number of declarations
615  offset += uint32_t_size;
616  for (uint32_t i : swTraceBuffer)
617  {
618  WriteUint32(buffer, offset, i); // Message declarations
619  offset += uint32_t_size;
620  }
621 
622  // Update the number of bytes written
623  numberOfBytesWritten = timelineDirectoryPacketSize;
624 
626 }
627 
629  uint64_t nameGuid,
630  unsigned char* buffer,
631  unsigned int remainingBufferSize,
632  unsigned int& numberOfBytesWritten)
633 {
634  // Initialize the output value
635  numberOfBytesWritten = 0;
636 
637  // Check that the given buffer is valid
638  if (buffer == nullptr || remainingBufferSize == 0)
639  {
641  }
642 
643  // Utils
644  unsigned int uint32_t_size = sizeof(uint32_t);
645  unsigned int uint64_t_size = sizeof(uint64_t);
646 
647  // decl_id of the timeline message
648  uint32_t declId = 2;
649 
650  // Calculate the length of the data (in bytes)
651  unsigned int dataSize = uint32_t_size + (uint64_t_size * 2); // decl_id + Profiling GUID + Name GUID
652 
653  // Check whether the timeline binary fits in the given buffer
654  if (dataSize > remainingBufferSize)
655  {
657  }
658 
659  // Initialize the offset for writing in the buffer
660  unsigned int offset = 0;
661 
662  // Write the timeline binary payload to the buffer
663  WriteUint32(buffer, offset, declId); // decl_id
664  offset += uint32_t_size;
665  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
666  offset += uint64_t_size;
667  WriteUint64(buffer, offset, nameGuid); // Name GUID
668 
669  // Update the number of bytes written
670  numberOfBytesWritten = dataSize;
671 
673 }
674 
676  int threadId,
677  uint64_t profilingGuid,
678  unsigned char* buffer,
679  unsigned int remainingBufferSize,
680  unsigned int& numberOfBytesWritten)
681 {
682  // Initialize the output value
683  numberOfBytesWritten = 0;
684  // Check that the given buffer is valid
685  if (buffer == nullptr || remainingBufferSize == 0)
686  {
688  }
689 
690  // Utils
691  unsigned int uint32_t_size = sizeof(uint32_t);
692  unsigned int uint64_t_size = sizeof(uint64_t);
693 
694  // decl_id of the timeline message
695  uint32_t declId = 4;
696 
697  // Calculate the length of the data (in bytes)
698  unsigned int timelineEventDataLength = uint32_t_size + // decl_id
699  uint64_t_size + // Timestamp
700  ThreadIdSize + // Thread id
701  uint64_t_size; // Profiling GUID
702 
703  // Check whether the timeline binary packet fits in the given buffer
704  if (timelineEventDataLength > remainingBufferSize)
705  {
707  }
708 
709  // Initialize the offset for writing in the buffer
710  unsigned int offset = 0;
711 
712  // Write the timeline binary payload to the buffer
713  WriteUint32(buffer, offset, declId); // decl_id
714  offset += uint32_t_size;
715  WriteUint64(buffer, offset, timestamp); // Timestamp
716  offset += uint64_t_size;
717  WriteBytes(buffer, offset, &threadId, ThreadIdSize); // Thread id
718  offset += ThreadIdSize;
719  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
720  offset += uint64_t_size;
721  // Update the number of bytes written
722  numberOfBytesWritten = timelineEventDataLength;
723 
725 }
726 
727 std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
728 {
729  return arm::pipe::CentreAlignFormatting(stringToPass, spacingWidth);
730 }
731 
732 void PrintDeviceDetails(const std::pair<const unsigned short, std::unique_ptr<Device>>& devicePair)
733 {
734  std::string body;
735 
736  body.append(CentreAlignFormatting(devicePair.second->m_Name, 20));
737  body.append(" | ");
738  body.append(CentreAlignFormatting(std::to_string(devicePair.first), 13));
739  body.append(" | ");
740  body.append(CentreAlignFormatting(std::to_string(devicePair.second->m_Cores), 10));
741  body.append("\n");
742 
743  std::cout << std::string(body.size(), '-') << "\n";
744  std::cout<< body;
745 }
746 
747 void PrintCounterSetDetails(const std::pair<const unsigned short, std::unique_ptr<CounterSet>>& counterSetPair)
748 {
749  std::string body;
750 
751  body.append(CentreAlignFormatting(counterSetPair.second->m_Name, 20));
752  body.append(" | ");
753  body.append(CentreAlignFormatting(std::to_string(counterSetPair.first), 13));
754  body.append(" | ");
755  body.append(CentreAlignFormatting(std::to_string(counterSetPair.second->m_Count), 10));
756  body.append("\n");
757 
758  std::cout << std::string(body.size(), '-') << "\n";
759 
760  std::cout<< body;
761 }
762 
763 void PrintCounterDetails(std::shared_ptr<Counter>& counter)
764 {
765  std::string body;
766 
767  body.append(CentreAlignFormatting(counter->m_Name, 20));
768  body.append(" | ");
769  body.append(CentreAlignFormatting(counter->m_Description, 50));
770  body.append(" | ");
771  body.append(CentreAlignFormatting(counter->m_Units, 14));
772  body.append(" | ");
773  body.append(CentreAlignFormatting(std::to_string(counter->m_Uid), 6));
774  body.append(" | ");
775  body.append(CentreAlignFormatting(std::to_string(counter->m_MaxCounterUid), 10));
776  body.append(" | ");
777  body.append(CentreAlignFormatting(std::to_string(counter->m_Class), 8));
778  body.append(" | ");
779  body.append(CentreAlignFormatting(std::to_string(counter->m_Interpolation), 14));
780  body.append(" | ");
781  body.append(CentreAlignFormatting(std::to_string(counter->m_Multiplier), 20));
782  body.append(" | ");
783  body.append(CentreAlignFormatting(std::to_string(counter->m_CounterSetUid), 16));
784  body.append(" | ");
785  body.append(CentreAlignFormatting(std::to_string(counter->m_DeviceUid), 14));
786 
787  body.append("\n");
788 
789  std::cout << std::string(body.size(), '-') << "\n";
790 
791  std::cout << body;
792 }
793 
794 void PrintCategoryDetails(const std::unique_ptr<Category>& category,
795  std::unordered_map<unsigned short, std::shared_ptr<Counter>> counterMap)
796 {
797  std::string categoryBody;
798  std::string categoryHeader;
799 
800  categoryHeader.append(CentreAlignFormatting("Name", 20));
801  categoryHeader.append(" | ");
802  categoryHeader.append(CentreAlignFormatting("Event Count", 14));
803  categoryHeader.append("\n");
804 
805  categoryBody.append(CentreAlignFormatting(category->m_Name, 20));
806  categoryBody.append(" | ");
807  categoryBody.append(CentreAlignFormatting(std::to_string(category->m_Counters.size()), 14));
808 
809  std::cout << "\n" << "\n";
810  std::cout << CentreAlignFormatting("CATEGORY", static_cast<int>(categoryHeader.size()));
811  std::cout << "\n";
812  std::cout << std::string(categoryHeader.size(), '=') << "\n";
813 
814  std::cout << categoryHeader;
815 
816  std::cout << std::string(categoryBody.size(), '-') << "\n";
817 
818  std::cout << categoryBody;
819 
820  std::string counterHeader;
821 
822  counterHeader.append(CentreAlignFormatting("Counter Name", 20));
823  counterHeader.append(" | ");
824  counterHeader.append(CentreAlignFormatting("Description", 50));
825  counterHeader.append(" | ");
826  counterHeader.append(CentreAlignFormatting("Units", 14));
827  counterHeader.append(" | ");
828  counterHeader.append(CentreAlignFormatting("UID", 6));
829  counterHeader.append(" | ");
830  counterHeader.append(CentreAlignFormatting("Max UID", 10));
831  counterHeader.append(" | ");
832  counterHeader.append(CentreAlignFormatting("Class", 8));
833  counterHeader.append(" | ");
834  counterHeader.append(CentreAlignFormatting("Interpolation", 14));
835  counterHeader.append(" | ");
836  counterHeader.append(CentreAlignFormatting("Multiplier", 20));
837  counterHeader.append(" | ");
838  counterHeader.append(CentreAlignFormatting("Counter set UID", 16));
839  counterHeader.append(" | ");
840  counterHeader.append(CentreAlignFormatting("Device UID", 14));
841  counterHeader.append("\n");
842 
843  std::cout << "\n" << "\n";
844  std::cout << CentreAlignFormatting("EVENTS IN CATEGORY: " + category->m_Name,
845  static_cast<int>(counterHeader.size()));
846  std::cout << "\n";
847  std::cout << std::string(counterHeader.size(), '=') << "\n";
848  std::cout << counterHeader;
849  for (auto& it: category->m_Counters) {
850  auto search = counterMap.find(it);
851  if(search != counterMap.end()) {
852  PrintCounterDetails(search->second);
853  }
854  }
855 }
856 
858 {
859  std::string devicesHeader;
860 
861  devicesHeader.append(CentreAlignFormatting("Device name", 20));
862  devicesHeader.append(" | ");
863  devicesHeader.append(CentreAlignFormatting("UID", 13));
864  devicesHeader.append(" | ");
865  devicesHeader.append(CentreAlignFormatting("Cores", 10));
866  devicesHeader.append("\n");
867 
868  std::cout << "\n" << "\n";
869  std::cout << CentreAlignFormatting("DEVICES", static_cast<int>(devicesHeader.size()));
870  std::cout << "\n";
871  std::cout << std::string(devicesHeader.size(), '=') << "\n";
872  std::cout << devicesHeader;
873  for (auto& it: counterDirectory.GetDevices()) {
874  PrintDeviceDetails(it);
875  }
876 
877  std::string counterSetHeader;
878 
879  counterSetHeader.append(CentreAlignFormatting("Counter set name", 20));
880  counterSetHeader.append(" | ");
881  counterSetHeader.append(CentreAlignFormatting("UID", 13));
882  counterSetHeader.append(" | ");
883  counterSetHeader.append(CentreAlignFormatting("Count", 10));
884  counterSetHeader.append("\n");
885 
886  std::cout << "\n" << "\n";
887  std::cout << CentreAlignFormatting("COUNTER SETS", static_cast<int>(counterSetHeader.size()));
888  std::cout << "\n";
889  std::cout << std::string(counterSetHeader.size(), '=') << "\n";
890 
891  std::cout << counterSetHeader;
892 
893  for (auto& it: counterDirectory.GetCounterSets()) {
895  }
896 
897  auto counters = counterDirectory.GetCounters();
898  for (auto& it: counterDirectory.GetCategories()) {
899  PrintCategoryDetails(it, counters);
900  }
901  std::cout << "\n";
902 }
903 
904 uint64_t GetTimestamp()
905 {
906 #if USE_CLOCK_MONOTONIC_RAW
907  using clock = MonotonicClockRaw;
908 #else
909  using clock = std::chrono::steady_clock;
910 #endif
911 
912  // Take a timestamp
913  auto timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(clock::now().time_since_epoch());
914 
915  return static_cast<uint64_t>(timestamp.count());
916 }
917 
918 arm::pipe::Packet ReceivePacket(const unsigned char* buffer, uint32_t length)
919 {
920  if (buffer == nullptr)
921  {
922  throw arm::pipe::ProfilingException("data buffer is nullptr");
923  }
924  if (length < 8)
925  {
926  throw arm::pipe::ProfilingException("length of data buffer is less than 8");
927  }
928 
929  uint32_t metadataIdentifier = 0;
930  std::memcpy(&metadataIdentifier, buffer, sizeof(metadataIdentifier));
931 
932  uint32_t dataLength = 0;
933  std::memcpy(&dataLength, buffer + 4u, sizeof(dataLength));
934 
935  std::unique_ptr<unsigned char[]> packetData;
936  if (dataLength > 0)
937  {
938  packetData = std::make_unique<unsigned char[]>(dataLength);
939  std::memcpy(packetData.get(), buffer + 8u, dataLength);
940  }
941 
942  return arm::pipe::Packet(metadataIdentifier, dataLength, packetData);
943 }
944 
945 } // namespace profiling
946 
947 } // namespace armnn
948 
949 namespace std
950 {
951 
952 bool operator==(const std::vector<uint8_t>& left, int right)
953 {
954  return std::memcmp(left.data(), &right, left.size()) == 0;
955 }
956 
957 } // namespace std
void WriteBytes(unsigned char *buffer, unsigned int offset, const void *value, unsigned int valueSize)
uint8_t ReadUint8(const unsigned char *buffer, unsigned int offset)
void WriteUint32(unsigned char *buffer, unsigned int offset, uint32_t value)
void ReadBytes(const unsigned char *buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
uint32_t ReadUint32(const unsigned char *buffer, unsigned int offset)
TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
std::string GetHardwareVersion()
bool operator==(const std::vector< uint8_t > &left, int right)
void WriteUint16(const IPacketBufferPtr &packetBuffer, unsigned int offset, uint16_t value)
void ReadBytes(const IPacketBufferPtr &packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
void WriteUint32(const IPacketBufferPtr &packetBuffer, unsigned int offset, uint32_t value)
uint64_t ReadUint64(const IPacketBufferPtr &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)
Creates a timeline packet header.
#define ARMNN_MINOR_VERSION
Definition: Version.hpp:14
std::string GetProcessName()
TimelinePacketStatus WriteTimelineRelationshipBinary(ProfilingRelationshipType relationshipType, uint64_t relationshipGuid, uint64_t headGuid, uint64_t tailGuid, uint64_t attributeGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
uint16_t ReadUint16(const IPacketBufferPtr &packetBuffer, unsigned int offset)
uint8_t ReadUint8(const IPacketBufferPtr &packetBuffer, unsigned int offset)
Copyright (c) 2021 ARM Limited and Contributors.
Head execution start depends on Tail execution completion.
void PrintDeviceDetails(const std::pair< const unsigned short, std::unique_ptr< Device >> &devicePair)
virtual const CounterSets & GetCounterSets() const =0
std::string GetSoftwareInfo()
arm::pipe::Packet ReceivePacket(const unsigned char *buffer, uint32_t length)
void WriteUint16(unsigned char *buffer, unsigned int offset, uint16_t value)
uint16_t ReadUint16(const unsigned char *buffer, unsigned int offset)
virtual const Categories & GetCategories() const =0
uint16_t GetNextUid(bool peekOnly)
void WriteUint8(unsigned char *buffer, unsigned int offset, uint8_t value)
virtual const Devices & GetDevices() const =0
TimelinePacketStatus WriteTimelineEventBinary(uint64_t timestamp, int threadId, uint64_t profilingGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
std::vector< uint16_t > GetNextCounterUids(uint16_t firstUid, uint16_t cores)
void WriteBytes(const IPacketBufferPtr &packetBuffer, unsigned int offset, const void *value, unsigned int valueSize)
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)
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
constexpr unsigned int ThreadIdSize
TimelinePacketStatus WriteTimelineEventClassBinary(uint64_t profilingGuid, uint64_t nameGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
void WriteUint8(const IPacketBufferPtr &packetBuffer, unsigned int offset, uint8_t value)
uint64_t ReadUint64(const unsigned char *buffer, unsigned int offset)
void WriteUint64(const std::unique_ptr< IPacketBuffer > &packetBuffer, unsigned int offset, uint64_t value)
uint32_t ReadUint32(const IPacketBufferPtr &packetBuffer, unsigned int offset)
void PrintCounterSetDetails(const std::pair< const unsigned short, std::unique_ptr< CounterSet >> &counterSetPair)
std::string GetSoftwareVersion()
std::pair< uint32_t, uint32_t > CreateTimelineMessagePacketHeader(unsigned int dataLength)
Creates a packet header for the timeline messages:
TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid, const std::string &label, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:35
void PrintCounterDetails(std::shared_ptr< Counter > &counter)
virtual const Counters & GetCounters() const =0
std::string CentreAlignFormatting(const std::string &stringToPass, const int spacingWidth)
void WriteUint64(unsigned char *buffer, unsigned int offset, uint64_t value)
TimelinePacketStatus WriteTimelineEntityBinary(uint64_t profilingGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
void PrintCounterDirectory(ICounterDirectory &counterDirectory)
#define ARMNN_MAJOR_VERSION
Definition: Version.hpp:13
std::unique_ptr< IPacketBuffer > IPacketBufferPtr
uint64_t GetTimestamp()