ArmNN
 20.02
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 
392 /// Creates a timeline packet header
393 ///
394 /// \params
395 /// packetFamiliy Timeline Packet Family
396 /// packetClass Timeline Packet Class
397 /// packetType Timeline Packet Type
398 /// streamId Stream identifier
399 /// seqeunceNumbered When non-zero the 4 bytes following the header is a u32 sequence number
400 /// dataLength Unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
401 ///
402 /// \returns
403 /// Pair of uint32_t containing word0 and word1 of the header
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 
432 /// Creates a packet header for the timeline messages:
433 /// * declareLabel
434 /// * declareEntity
435 /// * declareEventClass
436 /// * declareRelationship
437 /// * declareEvent
438 ///
439 /// \param
440 /// dataLength The length of the message body in bytes
441 ///
442 /// \returns
443 /// Pair of uint32_t containing word0 and word1 of the header
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 remainingBufferSize,
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 || remainingBufferSize == 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  // Check whether the timeline binary packet fits in the given buffer
490  if (timelineLabelPacketDataLength > remainingBufferSize)
491  {
493  }
494 
495  // Initialize the offset for writing in the buffer
496  unsigned int offset = 0;
497 
498  // Write decl_Id to the buffer
499  WriteUint32(buffer, offset, 0u);
500  offset += uint32_t_size;
501 
502  // Write the timeline binary packet payload to the buffer
503  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
504  offset += uint64_t_size;
505  for (uint32_t swTraceLabelWord : swTraceLabel)
506  {
507  WriteUint32(buffer, offset, swTraceLabelWord); // Label
508  offset += uint32_t_size;
509  }
510 
511  // Update the number of bytes written
512  numberOfBytesWritten = timelineLabelPacketDataLength;
513 
515 }
516 
518  unsigned char* buffer,
519  unsigned int remainingBufferSize,
520  unsigned int& numberOfBytesWritten)
521 {
522  // Initialize the output value
523  numberOfBytesWritten = 0;
524 
525  // Check that the given buffer is valid
526  if (buffer == nullptr || remainingBufferSize == 0)
527  {
529  }
530 
531  // Utils
532  unsigned int uint32_t_size = sizeof(uint32_t);
533  unsigned int uint64_t_size = sizeof(uint64_t);
534 
535  // Calculate the length of the data (in bytes)
536  unsigned int timelineEntityDataLength = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
537 
538  // Check whether the timeline binary packet fits in the given buffer
539  if (timelineEntityDataLength > remainingBufferSize)
540  {
542  }
543 
544  // Initialize the offset for writing in the buffer
545  unsigned int offset = 0;
546 
547  // Write the decl_Id to the buffer
548  WriteUint32(buffer, offset, 1u);
549  offset += uint32_t_size;
550 
551  // Write the timeline binary packet payload to the buffer
552  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
553 
554  // Update the number of bytes written
555  numberOfBytesWritten = timelineEntityDataLength;
556 
558 }
559 
561  uint64_t relationshipGuid,
562  uint64_t headGuid,
563  uint64_t tailGuid,
564  unsigned char* buffer,
565  unsigned int remainingBufferSize,
566  unsigned int& numberOfBytesWritten)
567 {
568  // Initialize the output value
569  numberOfBytesWritten = 0;
570 
571  // Check that the given buffer is valid
572  if (buffer == nullptr || remainingBufferSize == 0)
573  {
575  }
576 
577  // Utils
578  unsigned int uint32_t_size = sizeof(uint32_t);
579  unsigned int uint64_t_size = sizeof(uint64_t);
580 
581  // Calculate the length of the data (in bytes)
582  unsigned int timelineRelationshipDataLength = uint32_t_size * 2 + // decl_id + Relationship Type
583  uint64_t_size * 3; // Relationship GUID + Head GUID + tail GUID
584 
585  // Check whether the timeline binary fits in the given buffer
586  if (timelineRelationshipDataLength > remainingBufferSize)
587  {
589  }
590 
591  // Initialize the offset for writing in the buffer
592  unsigned int offset = 0;
593 
594  uint32_t relationshipTypeUint = 0;
595 
596  switch (relationshipType)
597  {
599  relationshipTypeUint = 0;
600  break;
602  relationshipTypeUint = 1;
603  break;
605  relationshipTypeUint = 2;
606  break;
608  relationshipTypeUint = 3;
609  break;
610  default:
611  throw InvalidArgumentException("Unknown relationship type given.");
612  }
613 
614  // Write the timeline binary payload to the buffer
615  // decl_id of the timeline message
616  uint32_t declId = 3;
617  WriteUint32(buffer, offset, declId); // decl_id
618  offset += uint32_t_size;
619  WriteUint32(buffer, offset, relationshipTypeUint); // Relationship Type
620  offset += uint32_t_size;
621  WriteUint64(buffer, offset, relationshipGuid); // GUID of this relationship
622  offset += uint64_t_size;
623  WriteUint64(buffer, offset, headGuid); // head of relationship GUID
624  offset += uint64_t_size;
625  WriteUint64(buffer, offset, tailGuid); // tail of relationship GUID
626 
627  // Update the number of bytes written
628  numberOfBytesWritten = timelineRelationshipDataLength;
629 
631 }
632 
634  unsigned int remainingBufferSize,
635  unsigned int& numberOfBytesWritten)
636 {
637  // Initialize the output value
638  numberOfBytesWritten = 0;
639 
640  // Check that the given buffer is valid
641  if (buffer == nullptr || remainingBufferSize == 0)
642  {
644  }
645 
646  // Utils
647  unsigned int uint8_t_size = sizeof(uint8_t);
648  unsigned int uint32_t_size = sizeof(uint32_t);
649  unsigned int uint64_t_size = sizeof(uint64_t);
650  unsigned int threadId_size = sizeof(std::thread::id);
651 
652  // The payload/data of the packet consists of swtrace event definitions encoded according
653  // to the swtrace directory specification. The messages being the five defined below:
654  //
655  // | decl_id | decl_name | ui_name | arg_types | arg_names |
656  // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
657  // | 0 | declareLabel | declare label | ps | guid,value |
658  // | 1 | declareEntity | declare entity | p | guid |
659  // | 2 | declareEventClass | declare event class | p | guid |
660  // | 3 | declareRelationship | declare relationship | Ippp | relationshipType,relationshipGuid, |
661  // | | | | | headGuid,tailGuid |
662  // | 4 | declareEvent | declare event | @tp | timestamp,threadId,eventGuid |
663  std::vector<std::vector<std::string>> timelineDirectoryMessages
664  {
665  { "0", "declareLabel", "declare label", "ps", "guid,value" },
666  { "1", "declareEntity", "declare entity", "p", "guid" },
667  { "2", "declareEventClass", "declare event class", "p", "guid" },
668  { "3", "declareRelationship", "declare relationship", "Ippp",
669  "relationshipType,relationshipGuid,headGuid,tailGuid" },
670  { "4", "declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid" }
671  };
672 
673  // Build the message declarations
674  std::vector<uint32_t> swTraceBuffer;
675  for (const auto& directoryComponent : timelineDirectoryMessages)
676  {
677  // decl_id
678  uint32_t declId = 0;
679  try
680  {
681  declId = boost::numeric_cast<uint32_t>(std::stoul(directoryComponent[0]));
682  }
683  catch (const std::exception&)
684  {
686  }
687  swTraceBuffer.push_back(declId);
688 
689  bool result = true;
690  result &= ConvertDirectoryComponent<SwTraceNameCharPolicy>(directoryComponent[1], swTraceBuffer); // decl_name
691  result &= ConvertDirectoryComponent<SwTraceCharPolicy> (directoryComponent[2], swTraceBuffer); // ui_name
692  result &= ConvertDirectoryComponent<SwTraceTypeCharPolicy>(directoryComponent[3], swTraceBuffer); // arg_types
693  result &= ConvertDirectoryComponent<SwTraceCharPolicy> (directoryComponent[4], swTraceBuffer); // arg_names
694  if (!result)
695  {
697  }
698  }
699 
700  unsigned int dataLength = 3 * uint8_t_size + // Stream header (3 bytes)
701  boost::numeric_cast<unsigned int>(swTraceBuffer.size()) *
702  uint32_t_size; // Trace directory (5 messages)
703 
704  // Calculate the timeline directory binary packet size (in bytes)
705  unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
706  dataLength; // Payload
707 
708  // Check whether the timeline directory binary packet fits in the given buffer
709  if (timelineDirectoryPacketSize > remainingBufferSize)
710  {
712  }
713 
714  // Create packet header
715  auto packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, boost::numeric_cast<uint32_t>(dataLength));
716 
717  // Initialize the offset for writing in the buffer
718  unsigned int offset = 0;
719 
720  // Write the timeline binary packet header to the buffer
721  WriteUint32(buffer, offset, packetHeader.first);
722  offset += uint32_t_size;
723  WriteUint32(buffer, offset, packetHeader.second);
724  offset += uint32_t_size;
725 
726  // Write the stream header
727  uint8_t streamVersion = 4;
728  uint8_t pointerBytes = boost::numeric_cast<uint8_t>(uint64_t_size); // All GUIDs are uint64_t
729  uint8_t threadIdBytes = boost::numeric_cast<uint8_t>(threadId_size);
730  switch (threadIdBytes)
731  {
732  case 4: // Typically Windows and Android
733  case 8: // Typically Linux
734  break; // Valid values
735  default:
736  return TimelinePacketStatus::Error; // Invalid value
737  }
738  WriteUint8(buffer, offset, streamVersion);
739  offset += uint8_t_size;
740  WriteUint8(buffer, offset, pointerBytes);
741  offset += uint8_t_size;
742  WriteUint8(buffer, offset, threadIdBytes);
743  offset += uint8_t_size;
744 
745  // Write the SWTrace directory
746  uint32_t numberOfDeclarations = boost::numeric_cast<uint32_t>(timelineDirectoryMessages.size());
747  WriteUint32(buffer, offset, numberOfDeclarations); // Number of declarations
748  offset += uint32_t_size;
749  for (uint32_t i : swTraceBuffer)
750  {
751  WriteUint32(buffer, offset, i); // Message declarations
752  offset += uint32_t_size;
753  }
754 
755  // Update the number of bytes written
756  numberOfBytesWritten = timelineDirectoryPacketSize;
757 
759 }
760 
762  unsigned char* buffer,
763  unsigned int remainingBufferSize,
764  unsigned int& numberOfBytesWritten)
765 {
766  // Initialize the output value
767  numberOfBytesWritten = 0;
768 
769  // Check that the given buffer is valid
770  if (buffer == nullptr || remainingBufferSize == 0)
771  {
773  }
774 
775  // Utils
776  unsigned int uint32_t_size = sizeof(uint32_t);
777  unsigned int uint64_t_size = sizeof(uint64_t);
778 
779  // decl_id of the timeline message
780  uint32_t declId = 2;
781 
782  // Calculate the length of the data (in bytes)
783  unsigned int dataSize = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
784 
785  // Check whether the timeline binary fits in the given buffer
786  if (dataSize > remainingBufferSize)
787  {
789  }
790 
791  // Initialize the offset for writing in the buffer
792  unsigned int offset = 0;
793 
794  // Write the timeline binary payload to the buffer
795  WriteUint32(buffer, offset, declId); // decl_id
796  offset += uint32_t_size;
797  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
798 
799  // Update the number of bytes written
800  numberOfBytesWritten = dataSize;
801 
803 }
804 
806  std::thread::id threadId,
807  uint64_t profilingGuid,
808  unsigned char* buffer,
809  unsigned int remainingBufferSize,
810  unsigned int& numberOfBytesWritten)
811 {
812  // Initialize the output value
813  numberOfBytesWritten = 0;
814  // Check that the given buffer is valid
815  if (buffer == nullptr || remainingBufferSize == 0)
816  {
818  }
819 
820  // Utils
821  unsigned int uint32_t_size = sizeof(uint32_t);
822  unsigned int uint64_t_size = sizeof(uint64_t);
823  unsigned int threadId_size = sizeof(std::thread::id);
824 
825  // decl_id of the timeline message
826  uint32_t declId = 4;
827 
828  // Calculate the length of the data (in bytes)
829  unsigned int timelineEventDataLength = uint32_t_size + // decl_id
830  uint64_t_size + // Timestamp
831  threadId_size + // Thread id
832  uint64_t_size; // Profiling GUID
833 
834  // Check whether the timeline binary packet fits in the given buffer
835  if (timelineEventDataLength > remainingBufferSize)
836  {
838  }
839 
840  // Initialize the offset for writing in the buffer
841  unsigned int offset = 0;
842 
843  // Write the timeline binary payload to the buffer
844  WriteUint32(buffer, offset, declId); // decl_id
845  offset += uint32_t_size;
846  WriteUint64(buffer, offset, timestamp); // Timestamp
847  offset += uint64_t_size;
848  WriteBytes(buffer, offset, &threadId, threadId_size); // Thread id
849  offset += threadId_size;
850  WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
851  offset += uint64_t_size;
852  // Update the number of bytes written
853  numberOfBytesWritten = timelineEventDataLength;
854 
856 }
857 
858 std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
859 {
860  std::stringstream outputStream, centrePadding;
861  int padding = spacingWidth - static_cast<int>(stringToPass.size());
862 
863  for (int i = 0; i < padding / 2; ++i)
864  {
865  centrePadding << " ";
866  }
867 
868  outputStream << centrePadding.str() << stringToPass << centrePadding.str();
869 
870  if (padding > 0 && padding %2 != 0)
871  {
872  outputStream << " ";
873  }
874 
875  return outputStream.str();
876 }
877 
878 void PrintDeviceDetails(const std::pair<const unsigned short, std::unique_ptr<Device>>& devicePair)
879 {
880  std::string body;
881 
882  body.append(CentreAlignFormatting(devicePair.second->m_Name, 20));
883  body.append(" | ");
884  body.append(CentreAlignFormatting(std::to_string(devicePair.first), 13));
885  body.append(" | ");
886  body.append(CentreAlignFormatting(std::to_string(devicePair.second->m_Cores), 10));
887  body.append("\n");
888 
889  std::cout << std::string(body.size(), '-') << "\n";
890  std::cout<< body;
891 }
892 
893 void PrintCounterSetDetails(const std::pair<const unsigned short, std::unique_ptr<CounterSet>>& counterSetPair)
894 {
895  std::string body;
896 
897  body.append(CentreAlignFormatting(counterSetPair.second->m_Name, 20));
898  body.append(" | ");
899  body.append(CentreAlignFormatting(std::to_string(counterSetPair.first), 13));
900  body.append(" | ");
901  body.append(CentreAlignFormatting(std::to_string(counterSetPair.second->m_Count), 10));
902  body.append("\n");
903 
904  std::cout << std::string(body.size(), '-') << "\n";
905 
906  std::cout<< body;
907 }
908 
909 void PrintCounterDetails(std::shared_ptr<Counter>& counter)
910 {
911  std::string body;
912 
913  body.append(CentreAlignFormatting(counter->m_Name, 20));
914  body.append(" | ");
915  body.append(CentreAlignFormatting(counter->m_Description, 50));
916  body.append(" | ");
917  body.append(CentreAlignFormatting(counter->m_Units, 14));
918  body.append(" | ");
919  body.append(CentreAlignFormatting(std::to_string(counter->m_Uid), 6));
920  body.append(" | ");
921  body.append(CentreAlignFormatting(std::to_string(counter->m_MaxCounterUid), 10));
922  body.append(" | ");
923  body.append(CentreAlignFormatting(std::to_string(counter->m_Class), 8));
924  body.append(" | ");
925  body.append(CentreAlignFormatting(std::to_string(counter->m_Interpolation), 14));
926  body.append(" | ");
927  body.append(CentreAlignFormatting(std::to_string(counter->m_Multiplier), 20));
928  body.append(" | ");
929  body.append(CentreAlignFormatting(std::to_string(counter->m_CounterSetUid), 16));
930  body.append(" | ");
931  body.append(CentreAlignFormatting(std::to_string(counter->m_DeviceUid), 14));
932 
933  body.append("\n");
934 
935  std::cout << std::string(body.size(), '-') << "\n";
936 
937  std::cout << body;
938 }
939 
940 void PrintCategoryDetails(const std::unique_ptr<Category>& category,
941  std::unordered_map<unsigned short, std::shared_ptr<Counter>> counterMap)
942 {
943  std::string categoryBody;
944  std::string categoryHeader;
945 
946  categoryHeader.append(CentreAlignFormatting("Name", 20));
947  categoryHeader.append(" | ");
948  categoryHeader.append(CentreAlignFormatting("Event Count", 14));
949  categoryHeader.append("\n");
950 
951  categoryBody.append(CentreAlignFormatting(category->m_Name, 20));
952  categoryBody.append(" | ");
953  categoryBody.append(CentreAlignFormatting(std::to_string(category->m_Counters.size()), 14));
954 
955  std::cout << "\n" << "\n";
956  std::cout << CentreAlignFormatting("CATEGORY", static_cast<int>(categoryHeader.size()));
957  std::cout << "\n";
958  std::cout << std::string(categoryHeader.size(), '=') << "\n";
959 
960  std::cout << categoryHeader;
961 
962  std::cout << std::string(categoryBody.size(), '-') << "\n";
963 
964  std::cout << categoryBody;
965 
966  std::string counterHeader;
967 
968  counterHeader.append(CentreAlignFormatting("Counter Name", 20));
969  counterHeader.append(" | ");
970  counterHeader.append(CentreAlignFormatting("Description", 50));
971  counterHeader.append(" | ");
972  counterHeader.append(CentreAlignFormatting("Units", 14));
973  counterHeader.append(" | ");
974  counterHeader.append(CentreAlignFormatting("UID", 6));
975  counterHeader.append(" | ");
976  counterHeader.append(CentreAlignFormatting("Max UID", 10));
977  counterHeader.append(" | ");
978  counterHeader.append(CentreAlignFormatting("Class", 8));
979  counterHeader.append(" | ");
980  counterHeader.append(CentreAlignFormatting("Interpolation", 14));
981  counterHeader.append(" | ");
982  counterHeader.append(CentreAlignFormatting("Multiplier", 20));
983  counterHeader.append(" | ");
984  counterHeader.append(CentreAlignFormatting("Counter set UID", 16));
985  counterHeader.append(" | ");
986  counterHeader.append(CentreAlignFormatting("Device UID", 14));
987  counterHeader.append("\n");
988 
989  std::cout << "\n" << "\n";
990  std::cout << CentreAlignFormatting("EVENTS IN CATEGORY: " + category->m_Name,
991  static_cast<int>(counterHeader.size()));
992  std::cout << "\n";
993  std::cout << std::string(counterHeader.size(), '=') << "\n";
994  std::cout << counterHeader;
995  for (auto& it: category->m_Counters) {
996  auto search = counterMap.find(it);
997  if(search != counterMap.end()) {
998  PrintCounterDetails(search->second);
999  }
1000  }
1001 }
1002 
1004 {
1005  std::string devicesHeader;
1006 
1007  devicesHeader.append(CentreAlignFormatting("Device name", 20));
1008  devicesHeader.append(" | ");
1009  devicesHeader.append(CentreAlignFormatting("UID", 13));
1010  devicesHeader.append(" | ");
1011  devicesHeader.append(CentreAlignFormatting("Cores", 10));
1012  devicesHeader.append("\n");
1013 
1014  std::cout << "\n" << "\n";
1015  std::cout << CentreAlignFormatting("DEVICES", static_cast<int>(devicesHeader.size()));
1016  std::cout << "\n";
1017  std::cout << std::string(devicesHeader.size(), '=') << "\n";
1018  std::cout << devicesHeader;
1019  for (auto& it: counterDirectory.GetDevices()) {
1020  PrintDeviceDetails(it);
1021  }
1022 
1023  std::string counterSetHeader;
1024 
1025  counterSetHeader.append(CentreAlignFormatting("Counter set name", 20));
1026  counterSetHeader.append(" | ");
1027  counterSetHeader.append(CentreAlignFormatting("UID", 13));
1028  counterSetHeader.append(" | ");
1029  counterSetHeader.append(CentreAlignFormatting("Count", 10));
1030  counterSetHeader.append("\n");
1031 
1032  std::cout << "\n" << "\n";
1033  std::cout << CentreAlignFormatting("COUNTER SETS", static_cast<int>(counterSetHeader.size()));
1034  std::cout << "\n";
1035  std::cout << std::string(counterSetHeader.size(), '=') << "\n";
1036 
1037  std::cout << counterSetHeader;
1038 
1039  for (auto& it: counterDirectory.GetCounterSets()) {
1041  }
1042 
1043  auto counters = counterDirectory.GetCounters();
1044  for (auto& it: counterDirectory.GetCategories()) {
1045  PrintCategoryDetails(it, counters);
1046  }
1047  std::cout << "\n";
1048 }
1049 
1050 uint64_t GetTimestamp()
1051 {
1052 #if USE_CLOCK_MONOTONIC_RAW
1053  using clock = MonotonicClockRaw;
1054 #else
1055  using clock = std::chrono::steady_clock;
1056 #endif
1057 
1058  // Take a timestamp
1059  auto timestamp = clock::now();
1060 
1061  return static_cast<uint64_t>(timestamp.time_since_epoch().count());
1062 }
1063 
1064 } // namespace profiling
1065 
1066 } // namespace armnn
1067 
1068 namespace std
1069 {
1070 
1071 bool operator==(const std::vector<uint8_t>& left, std::thread::id right)
1072 {
1073  return std::memcmp(left.data(), &right, left.size()) == 0;
1074 }
1075 
1076 } // namespace std
#define ARMNN_VERSION
ARMNN_VERSION: "YYYYMMPP" where: YYYY = 4-digit year number MM = 2-digit month number PP = 2-digit pa...
Definition: Version.hpp:24
bool operator==(const std::vector< uint8_t > &left, std::thread::id right)
TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
std::string GetHardwareVersion()
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.
std::string GetProcessName()
uint16_t ReadUint16(const IPacketBufferPtr &packetBuffer, unsigned int offset)
uint8_t ReadUint8(const IPacketBufferPtr &packetBuffer, unsigned int offset)
Copyright (c) 2020 ARM Limited.
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()
TimelinePacketStatus WriteTimelineRelationshipBinary(ProfilingRelationshipType relationshipType, uint64_t relationshipGuid, uint64_t headGuid, uint64_t tailGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
virtual const Categories & GetCategories() const =0
uint16_t GetNextUid(bool peekOnly)
SwTraceMessage ReadSwTraceMessage(const unsigned char *packetBuffer, unsigned int &offset)
virtual const Devices & GetDevices() const =0
std::vector< std::string > m_ArgNames
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)
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:33
void WriteUint8(const IPacketBufferPtr &packetBuffer, unsigned int offset, uint8_t value)
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()
TimelinePacketStatus WriteTimelineEventClassBinary(uint64_t profilingGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
uint32_t CalculateSizeOfPaddedSwString(const std::string &str)
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)
TimelinePacketStatus WriteTimelineEventBinary(uint64_t timestamp, std::thread::id threadId, uint64_t profilingGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
void PrintCounterDetails(std::shared_ptr< Counter > &counter)
virtual const Counters & GetCounters() const =0
std::string CentreAlignFormatting(const std::string &stringToPass, const int spacingWidth)
TimelinePacketStatus WriteTimelineEntityBinary(uint64_t profilingGuid, unsigned char *buffer, unsigned int remainingBufferSize, unsigned int &numberOfBytesWritten)
void PrintCounterDirectory(ICounterDirectory &counterDirectory)
std::unique_ptr< IPacketBuffer > IPacketBufferPtr