IVGCVSW-4699 Force timestamps to always be in nanoseconds
[platform/upstream/armnn.git] / src / profiling / ProfilingUtils.cpp
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 <armnn/utility/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     ARMNN_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 & 0x0000003F ) << 26 )|
100            (( packetId & 0x000003FF )     << 16 );
101 }
102
103 void WriteUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint64_t value)
104 {
105     ARMNN_ASSERT(packetBuffer);
106
107     WriteUint64(packetBuffer->GetWritableData(), offset, value);
108 }
109
110 void WriteUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint32_t value)
111 {
112     ARMNN_ASSERT(packetBuffer);
113
114     WriteUint32(packetBuffer->GetWritableData(), offset, value);
115 }
116
117 void WriteUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint16_t value)
118 {
119     ARMNN_ASSERT(packetBuffer);
120
121     WriteUint16(packetBuffer->GetWritableData(), offset, value);
122 }
123
124 void WriteUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint8_t value)
125 {
126     ARMNN_ASSERT(packetBuffer);
127
128     WriteUint8(packetBuffer->GetWritableData(), offset, value);
129 }
130
131 void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize)
132 {
133     ARMNN_ASSERT(buffer);
134     ARMNN_ASSERT(value);
135
136     for (unsigned int i = 0; i < valueSize; i++, offset++)
137     {
138         buffer[offset] = *(reinterpret_cast<const unsigned char*>(value) + i);
139     }
140 }
141
142 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
143 {
144     ARMNN_ASSERT(buffer);
145
146     buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
147     buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
148     buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
149     buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
150     buffer[offset + 4] = static_cast<unsigned char>((value >> 32) & 0xFF);
151     buffer[offset + 5] = static_cast<unsigned char>((value >> 40) & 0xFF);
152     buffer[offset + 6] = static_cast<unsigned char>((value >> 48) & 0xFF);
153     buffer[offset + 7] = static_cast<unsigned char>((value >> 56) & 0xFF);
154 }
155
156 void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value)
157 {
158     ARMNN_ASSERT(buffer);
159
160     buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
161     buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
162     buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
163     buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
164 }
165
166 void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value)
167 {
168     ARMNN_ASSERT(buffer);
169
170     buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
171     buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
172 }
173
174 void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value)
175 {
176     ARMNN_ASSERT(buffer);
177
178     buffer[offset] = static_cast<unsigned char>(value);
179 }
180
181 void ReadBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
182 {
183     ARMNN_ASSERT(packetBuffer);
184
185     ReadBytes(packetBuffer->GetReadableData(), offset, valueSize, outValue);
186 }
187
188 uint64_t ReadUint64(const IPacketBufferPtr& packetBuffer, unsigned int offset)
189 {
190     ARMNN_ASSERT(packetBuffer);
191
192     return ReadUint64(packetBuffer->GetReadableData(), offset);
193 }
194
195 uint32_t ReadUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset)
196 {
197     ARMNN_ASSERT(packetBuffer);
198
199     return ReadUint32(packetBuffer->GetReadableData(), offset);
200 }
201
202 uint16_t ReadUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset)
203 {
204     ARMNN_ASSERT(packetBuffer);
205
206     return ReadUint16(packetBuffer->GetReadableData(), offset);
207 }
208
209 uint8_t ReadUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset)
210 {
211     ARMNN_ASSERT(packetBuffer);
212
213     return ReadUint8(packetBuffer->GetReadableData(), offset);
214 }
215
216 void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
217 {
218     ARMNN_ASSERT(buffer);
219     ARMNN_ASSERT(outValue);
220
221     for (unsigned int i = 0; i < valueSize; i++, offset++)
222     {
223         outValue[i] = static_cast<uint8_t>(buffer[offset]);
224     }
225 }
226
227 uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
228 {
229     ARMNN_ASSERT(buffer);
230
231     uint64_t value = 0;
232     value  = static_cast<uint64_t>(buffer[offset]);
233     value |= static_cast<uint64_t>(buffer[offset + 1]) << 8;
234     value |= static_cast<uint64_t>(buffer[offset + 2]) << 16;
235     value |= static_cast<uint64_t>(buffer[offset + 3]) << 24;
236     value |= static_cast<uint64_t>(buffer[offset + 4]) << 32;
237     value |= static_cast<uint64_t>(buffer[offset + 5]) << 40;
238     value |= static_cast<uint64_t>(buffer[offset + 6]) << 48;
239     value |= static_cast<uint64_t>(buffer[offset + 7]) << 56;
240
241     return value;
242 }
243
244 uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset)
245 {
246     ARMNN_ASSERT(buffer);
247
248     uint32_t value = 0;
249     value  = static_cast<uint32_t>(buffer[offset]);
250     value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
251     value |= static_cast<uint32_t>(buffer[offset + 2]) << 16;
252     value |= static_cast<uint32_t>(buffer[offset + 3]) << 24;
253     return value;
254 }
255
256 uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset)
257 {
258     ARMNN_ASSERT(buffer);
259
260     uint32_t value = 0;
261     value  = static_cast<uint32_t>(buffer[offset]);
262     value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
263     return static_cast<uint16_t>(value);
264 }
265
266 uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset)
267 {
268     ARMNN_ASSERT(buffer);
269
270     return buffer[offset];
271 }
272
273 std::string GetSoftwareInfo()
274 {
275     return std::string("ArmNN");
276 }
277
278 std::string GetHardwareVersion()
279 {
280     return std::string();
281 }
282
283 std::string GetSoftwareVersion()
284 {
285     std::string armnnVersion(ARMNN_VERSION);
286     std::string result = "Armnn " + armnnVersion.substr(2,2) + "." + armnnVersion.substr(4,2);
287     return result;
288 }
289
290 std::string GetProcessName()
291 {
292     std::ifstream comm("/proc/self/comm");
293     std::string name;
294     getline(comm, name);
295     return name;
296 }
297
298 // Calculate the actual length an SwString will be including the terminating null character
299 // padding to bring it to the next uint32_t boundary but minus the leading uint32_t encoding
300 // the size to allow the offset to be correctly updated when decoding a binary packet.
301 uint32_t CalculateSizeOfPaddedSwString(const std::string& str)
302 {
303     std::vector<uint32_t> swTraceString;
304     StringToSwTraceString<SwTraceCharPolicy>(str, swTraceString);
305     unsigned int uint32_t_size = sizeof(uint32_t);
306     uint32_t size = (boost::numeric_cast<uint32_t>(swTraceString.size()) - 1) * uint32_t_size;
307     return size;
308 }
309
310 // Read TimelineMessageDirectoryPacket from given IPacketBuffer and offset
311 SwTraceMessage ReadSwTraceMessage(const unsigned char* packetBuffer, unsigned int& offset)
312 {
313     ARMNN_ASSERT(packetBuffer);
314
315     unsigned int uint32_t_size = sizeof(uint32_t);
316
317     SwTraceMessage swTraceMessage;
318
319     // Read the decl_id
320     uint32_t readDeclId = ReadUint32(packetBuffer, offset);
321     swTraceMessage.m_Id = readDeclId;
322
323     // SWTrace "namestring" format
324     // length of the string (first 4 bytes) + string + null terminator
325
326     // Check the decl_name
327     offset += uint32_t_size;
328     uint32_t swTraceDeclNameLength = ReadUint32(packetBuffer, offset);
329
330     offset += uint32_t_size;
331     std::vector<unsigned char> swTraceStringBuffer(swTraceDeclNameLength - 1);
332     std::memcpy(swTraceStringBuffer.data(),
333                 packetBuffer + offset, swTraceStringBuffer.size());
334
335     swTraceMessage.m_Name.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // name
336
337     // Check the ui_name
338     offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_Name);
339     uint32_t swTraceUINameLength = ReadUint32(packetBuffer, offset);
340
341     offset += uint32_t_size;
342     swTraceStringBuffer.resize(swTraceUINameLength - 1);
343     std::memcpy(swTraceStringBuffer.data(),
344                 packetBuffer  + offset, swTraceStringBuffer.size());
345
346     swTraceMessage.m_UiName.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // ui_name
347
348     // Check arg_types
349     offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_UiName);
350     uint32_t swTraceArgTypesLength = ReadUint32(packetBuffer, offset);
351
352     offset += uint32_t_size;
353     swTraceStringBuffer.resize(swTraceArgTypesLength - 1);
354     std::memcpy(swTraceStringBuffer.data(),
355                 packetBuffer  + offset, swTraceStringBuffer.size());
356
357     swTraceMessage.m_ArgTypes.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // arg_types
358
359     std::string swTraceString(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
360
361     // Check arg_names
362     offset += CalculateSizeOfPaddedSwString(swTraceString);
363     uint32_t swTraceArgNamesLength = ReadUint32(packetBuffer, offset);
364
365     offset += uint32_t_size;
366     swTraceStringBuffer.resize(swTraceArgNamesLength - 1);
367     std::memcpy(swTraceStringBuffer.data(),
368                 packetBuffer  + offset, swTraceStringBuffer.size());
369
370     swTraceString.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
371     std::stringstream stringStream(swTraceString);
372     std::string argName;
373     while (std::getline(stringStream, argName, ','))
374     {
375         swTraceMessage.m_ArgNames.push_back(argName);
376     }
377
378     offset += CalculateSizeOfPaddedSwString(swTraceString);
379
380     return swTraceMessage;
381 }
382
383 /// Creates a timeline packet header
384 ///
385 /// \params
386 ///   packetFamiliy     Timeline Packet Family
387 ///   packetClass       Timeline Packet Class
388 ///   packetType        Timeline Packet Type
389 ///   streamId          Stream identifier
390 ///   seqeunceNumbered  When non-zero the 4 bytes following the header is a u32 sequence number
391 ///   dataLength        Unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
392 ///
393 /// \returns
394 ///   Pair of uint32_t containing word0 and word1 of the header
395 std::pair<uint32_t, uint32_t> CreateTimelinePacketHeader(uint32_t packetFamily,
396                                                          uint32_t packetClass,
397                                                          uint32_t packetType,
398                                                          uint32_t streamId,
399                                                          uint32_t sequenceNumbered,
400                                                          uint32_t dataLength)
401 {
402     // Packet header word 0:
403     // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
404     // 19:25 [7] packet_class: packet class
405     // 16:18 [3] packet_type: packet type
406     // 8:15  [8] reserved: all zeros
407     // 0:7   [8] stream_id: stream identifier
408     uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
409                                  ((packetClass  & 0x0000007F) << 19) |
410                                  ((packetType   & 0x00000007) << 16) |
411                                  ((streamId     & 0x00000007) <<  0);
412
413     // Packet header word 1:
414     // 25:31 [7]  reserved: all zeros
415     // 24    [1]  sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
416     // 0:23  [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
417     uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
418                                  ((dataLength       & 0x00FFFFFF) <<  0);
419
420     return std::make_pair(packetHeaderWord0, packetHeaderWord1);
421 }
422
423 /// Creates a packet header for the timeline messages:
424 /// * declareLabel
425 /// * declareEntity
426 /// * declareEventClass
427 /// * declareRelationship
428 /// * declareEvent
429 ///
430 /// \param
431 ///   dataLength The length of the message body in bytes
432 ///
433 /// \returns
434 ///   Pair of uint32_t containing word0 and word1 of the header
435 std::pair<uint32_t, uint32_t> CreateTimelineMessagePacketHeader(unsigned int dataLength)
436 {
437     return CreateTimelinePacketHeader(1,           // Packet family
438                                       0,           // Packet class
439                                       1,           // Packet type
440                                       0,           // Stream id
441                                       0,           // Sequence number
442                                       dataLength); // Data length
443 }
444
445 TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid,
446                                                     const std::string& label,
447                                                     unsigned char* buffer,
448                                                     unsigned int remainingBufferSize,
449                                                     unsigned int& numberOfBytesWritten)
450 {
451     // Initialize the output value
452     numberOfBytesWritten = 0;
453
454     // Check that the given buffer is valid
455     if (buffer == nullptr || remainingBufferSize == 0)
456     {
457         return TimelinePacketStatus::BufferExhaustion;
458     }
459
460     // Utils
461     unsigned int uint32_t_size = sizeof(uint32_t);
462     unsigned int uint64_t_size = sizeof(uint64_t);
463
464     // Convert the label into a SWTrace string
465     std::vector<uint32_t> swTraceLabel;
466     bool result = StringToSwTraceString<SwTraceCharPolicy>(label, swTraceLabel);
467     if (!result)
468     {
469         return TimelinePacketStatus::Error;
470     }
471
472     // Calculate the size of the SWTrace string label (in bytes)
473     unsigned int swTraceLabelSize = boost::numeric_cast<unsigned int>(swTraceLabel.size()) * uint32_t_size;
474
475     // Calculate the length of the data (in bytes)
476     unsigned int timelineLabelPacketDataLength = uint32_t_size +   // decl_Id
477                                                  uint64_t_size +   // Profiling GUID
478                                                  swTraceLabelSize; // Label
479
480     // Check whether the timeline binary packet fits in the given buffer
481     if (timelineLabelPacketDataLength > remainingBufferSize)
482     {
483         return TimelinePacketStatus::BufferExhaustion;
484     }
485
486     // Initialize the offset for writing in the buffer
487     unsigned int offset = 0;
488
489     // Write decl_Id to the buffer
490     WriteUint32(buffer, offset, 0u);
491     offset += uint32_t_size;
492
493     // Write the timeline binary packet payload to the buffer
494     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
495     offset += uint64_t_size;
496     for (uint32_t swTraceLabelWord : swTraceLabel)
497     {
498         WriteUint32(buffer, offset, swTraceLabelWord); // Label
499         offset += uint32_t_size;
500     }
501
502     // Update the number of bytes written
503     numberOfBytesWritten = timelineLabelPacketDataLength;
504
505     return TimelinePacketStatus::Ok;
506 }
507
508 TimelinePacketStatus WriteTimelineEntityBinary(uint64_t profilingGuid,
509                                                unsigned char* buffer,
510                                                unsigned int remainingBufferSize,
511                                                unsigned int& numberOfBytesWritten)
512 {
513     // Initialize the output value
514     numberOfBytesWritten = 0;
515
516     // Check that the given buffer is valid
517     if (buffer == nullptr || remainingBufferSize == 0)
518     {
519         return TimelinePacketStatus::BufferExhaustion;
520     }
521
522     // Utils
523     unsigned int uint32_t_size = sizeof(uint32_t);
524     unsigned int uint64_t_size = sizeof(uint64_t);
525
526     // Calculate the length of the data (in bytes)
527     unsigned int timelineEntityDataLength = uint32_t_size + uint64_t_size;  // decl_id + Profiling GUID
528
529     // Check whether the timeline binary packet fits in the given buffer
530     if (timelineEntityDataLength > remainingBufferSize)
531     {
532         return TimelinePacketStatus::BufferExhaustion;
533     }
534
535     // Initialize the offset for writing in the buffer
536     unsigned int offset = 0;
537
538     // Write the decl_Id to the buffer
539     WriteUint32(buffer, offset, 1u);
540     offset += uint32_t_size;
541
542     // Write the timeline binary packet payload to the buffer
543     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
544
545     // Update the number of bytes written
546     numberOfBytesWritten = timelineEntityDataLength;
547
548     return TimelinePacketStatus::Ok;
549 }
550
551 TimelinePacketStatus WriteTimelineRelationshipBinary(ProfilingRelationshipType relationshipType,
552                                                      uint64_t relationshipGuid,
553                                                      uint64_t headGuid,
554                                                      uint64_t tailGuid,
555                                                      unsigned char* buffer,
556                                                      unsigned int remainingBufferSize,
557                                                      unsigned int& numberOfBytesWritten)
558 {
559     // Initialize the output value
560     numberOfBytesWritten = 0;
561
562     // Check that the given buffer is valid
563     if (buffer == nullptr || remainingBufferSize == 0)
564     {
565         return TimelinePacketStatus::BufferExhaustion;
566     }
567
568     // Utils
569     unsigned int uint32_t_size = sizeof(uint32_t);
570     unsigned int uint64_t_size = sizeof(uint64_t);
571
572     // Calculate the length of the data (in bytes)
573     unsigned int timelineRelationshipDataLength = uint32_t_size * 2 + // decl_id + Relationship Type
574                                                   uint64_t_size * 3;  // Relationship GUID + Head GUID + tail GUID
575
576     // Check whether the timeline binary fits in the given buffer
577     if (timelineRelationshipDataLength > remainingBufferSize)
578     {
579         return TimelinePacketStatus::BufferExhaustion;
580     }
581
582     // Initialize the offset for writing in the buffer
583     unsigned int offset = 0;
584
585     uint32_t relationshipTypeUint = 0;
586
587     switch (relationshipType)
588     {
589         case ProfilingRelationshipType::RetentionLink:
590             relationshipTypeUint = 0;
591             break;
592         case ProfilingRelationshipType::ExecutionLink:
593             relationshipTypeUint = 1;
594             break;
595         case ProfilingRelationshipType::DataLink:
596             relationshipTypeUint = 2;
597             break;
598         case ProfilingRelationshipType::LabelLink:
599             relationshipTypeUint = 3;
600             break;
601         default:
602             throw InvalidArgumentException("Unknown relationship type given.");
603     }
604
605     // Write the timeline binary payload to the buffer
606     // decl_id of the timeline message
607     uint32_t declId = 3;
608     WriteUint32(buffer, offset, declId); // decl_id
609     offset += uint32_t_size;
610     WriteUint32(buffer, offset, relationshipTypeUint); // Relationship Type
611     offset += uint32_t_size;
612     WriteUint64(buffer, offset, relationshipGuid); // GUID of this relationship
613     offset += uint64_t_size;
614     WriteUint64(buffer, offset, headGuid); // head of relationship GUID
615     offset += uint64_t_size;
616     WriteUint64(buffer, offset, tailGuid); // tail of relationship GUID
617
618     // Update the number of bytes written
619     numberOfBytesWritten = timelineRelationshipDataLength;
620
621     return TimelinePacketStatus::Ok;
622 }
623
624 TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char* buffer,
625                                                           unsigned int remainingBufferSize,
626                                                           unsigned int& numberOfBytesWritten)
627 {
628     // Initialize the output value
629     numberOfBytesWritten = 0;
630
631     // Check that the given buffer is valid
632     if (buffer == nullptr || remainingBufferSize == 0)
633     {
634         return TimelinePacketStatus::BufferExhaustion;
635     }
636
637     // Utils
638     unsigned int uint8_t_size  = sizeof(uint8_t);
639     unsigned int uint32_t_size = sizeof(uint32_t);
640     unsigned int uint64_t_size = sizeof(uint64_t);
641     unsigned int threadId_size = sizeof(std::thread::id);
642
643     // The payload/data of the packet consists of swtrace event definitions encoded according
644     // to the swtrace directory specification. The messages being the five defined below:
645     //
646     // |  decl_id  |     decl_name       |      ui_name          |  arg_types  |            arg_names                |
647     // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
648     // |    0      |   declareLabel      |   declare label       |    ps       |  guid,value                         |
649     // |    1      |   declareEntity     |   declare entity      |    p        |  guid                               |
650     // |    2      | declareEventClass   |  declare event class  |    p        |  guid                               |
651     // |    3      | declareRelationship | declare relationship  |    Ippp     |  relationshipType,relationshipGuid, |
652     // |           |                     |                       |             |  headGuid,tailGuid                  |
653     // |    4      |   declareEvent      |   declare event       |    @tp      |  timestamp,threadId,eventGuid       |
654     std::vector<std::vector<std::string>> timelineDirectoryMessages
655     {
656         { "0", "declareLabel", "declare label", "ps", "guid,value" },
657         { "1", "declareEntity", "declare entity", "p", "guid" },
658         { "2", "declareEventClass", "declare event class", "p", "guid" },
659         { "3", "declareRelationship", "declare relationship", "Ippp",
660           "relationshipType,relationshipGuid,headGuid,tailGuid" },
661         { "4", "declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid" }
662     };
663
664     // Build the message declarations
665     std::vector<uint32_t> swTraceBuffer;
666     for (const auto& directoryComponent : timelineDirectoryMessages)
667     {
668         // decl_id
669         uint32_t declId = 0;
670         try
671         {
672             declId = boost::numeric_cast<uint32_t>(std::stoul(directoryComponent[0]));
673         }
674         catch (const std::exception&)
675         {
676             return TimelinePacketStatus::Error;
677         }
678         swTraceBuffer.push_back(declId);
679
680         bool result = true;
681         result &= ConvertDirectoryComponent<SwTraceNameCharPolicy>(directoryComponent[1], swTraceBuffer); // decl_name
682         result &= ConvertDirectoryComponent<SwTraceCharPolicy>    (directoryComponent[2], swTraceBuffer); // ui_name
683         result &= ConvertDirectoryComponent<SwTraceTypeCharPolicy>(directoryComponent[3], swTraceBuffer); // arg_types
684         result &= ConvertDirectoryComponent<SwTraceCharPolicy>    (directoryComponent[4], swTraceBuffer); // arg_names
685         if (!result)
686         {
687             return TimelinePacketStatus::Error;
688         }
689     }
690
691     unsigned int dataLength = 3 * uint8_t_size +  // Stream header (3 bytes)
692                               boost::numeric_cast<unsigned int>(swTraceBuffer.size()) *
693                                   uint32_t_size; // Trace directory (5 messages)
694
695     // Calculate the timeline directory binary packet size (in bytes)
696     unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
697                                                dataLength;         // Payload
698
699     // Check whether the timeline directory binary packet fits in the given buffer
700     if (timelineDirectoryPacketSize > remainingBufferSize)
701     {
702         return TimelinePacketStatus::BufferExhaustion;
703     }
704
705     // Create packet header
706     auto packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, boost::numeric_cast<uint32_t>(dataLength));
707
708     // Initialize the offset for writing in the buffer
709     unsigned int offset = 0;
710
711     // Write the timeline binary packet header to the buffer
712     WriteUint32(buffer, offset, packetHeader.first);
713     offset += uint32_t_size;
714     WriteUint32(buffer, offset, packetHeader.second);
715     offset += uint32_t_size;
716
717     // Write the stream header
718     uint8_t streamVersion = 4;
719     uint8_t pointerBytes  = boost::numeric_cast<uint8_t>(uint64_t_size); // All GUIDs are uint64_t
720     uint8_t threadIdBytes = boost::numeric_cast<uint8_t>(threadId_size);
721     switch (threadIdBytes)
722     {
723     case 4: // Typically Windows and Android
724     case 8: // Typically Linux
725         break; // Valid values
726     default:
727         return TimelinePacketStatus::Error; // Invalid value
728     }
729     WriteUint8(buffer, offset, streamVersion);
730     offset += uint8_t_size;
731     WriteUint8(buffer, offset, pointerBytes);
732     offset += uint8_t_size;
733     WriteUint8(buffer, offset, threadIdBytes);
734     offset += uint8_t_size;
735
736     // Write the SWTrace directory
737     uint32_t numberOfDeclarations = boost::numeric_cast<uint32_t>(timelineDirectoryMessages.size());
738     WriteUint32(buffer, offset, numberOfDeclarations); // Number of declarations
739     offset += uint32_t_size;
740     for (uint32_t i : swTraceBuffer)
741     {
742         WriteUint32(buffer, offset, i); // Message declarations
743         offset += uint32_t_size;
744     }
745
746     // Update the number of bytes written
747     numberOfBytesWritten = timelineDirectoryPacketSize;
748
749     return TimelinePacketStatus::Ok;
750 }
751
752 TimelinePacketStatus WriteTimelineEventClassBinary(uint64_t profilingGuid,
753                                                    unsigned char* buffer,
754                                                    unsigned int remainingBufferSize,
755                                                    unsigned int& numberOfBytesWritten)
756 {
757     // Initialize the output value
758     numberOfBytesWritten = 0;
759
760     // Check that the given buffer is valid
761     if (buffer == nullptr || remainingBufferSize == 0)
762     {
763         return TimelinePacketStatus::BufferExhaustion;
764     }
765
766     // Utils
767     unsigned int uint32_t_size = sizeof(uint32_t);
768     unsigned int uint64_t_size = sizeof(uint64_t);
769
770     // decl_id of the timeline message
771     uint32_t declId = 2;
772
773     // Calculate the length of the data (in bytes)
774     unsigned int dataSize = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
775
776     // Check whether the timeline binary fits in the given buffer
777     if (dataSize > remainingBufferSize)
778     {
779         return TimelinePacketStatus::BufferExhaustion;
780     }
781
782     // Initialize the offset for writing in the buffer
783     unsigned int offset = 0;
784
785     // Write the timeline binary payload to the buffer
786     WriteUint32(buffer, offset, declId);        // decl_id
787     offset += uint32_t_size;
788     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
789
790     // Update the number of bytes written
791     numberOfBytesWritten = dataSize;
792
793     return TimelinePacketStatus::Ok;
794 }
795
796 TimelinePacketStatus WriteTimelineEventBinary(uint64_t timestamp,
797                                               std::thread::id threadId,
798                                               uint64_t profilingGuid,
799                                               unsigned char* buffer,
800                                               unsigned int remainingBufferSize,
801                                               unsigned int& numberOfBytesWritten)
802 {
803     // Initialize the output value
804     numberOfBytesWritten = 0;
805     // Check that the given buffer is valid
806     if (buffer == nullptr || remainingBufferSize == 0)
807     {
808         return TimelinePacketStatus::BufferExhaustion;
809     }
810
811     // Utils
812     unsigned int uint32_t_size = sizeof(uint32_t);
813     unsigned int uint64_t_size = sizeof(uint64_t);
814     unsigned int threadId_size = sizeof(std::thread::id);
815
816     // decl_id of the timeline message
817     uint32_t declId = 4;
818
819     // Calculate the length of the data (in bytes)
820     unsigned int timelineEventDataLength = uint32_t_size + // decl_id
821                                            uint64_t_size + // Timestamp
822                                            threadId_size + // Thread id
823                                            uint64_t_size;  // Profiling GUID
824
825     // Check whether the timeline binary packet fits in the given buffer
826     if (timelineEventDataLength > remainingBufferSize)
827     {
828         return TimelinePacketStatus::BufferExhaustion;
829     }
830
831     // Initialize the offset for writing in the buffer
832     unsigned int offset = 0;
833
834     // Write the timeline binary payload to the buffer
835     WriteUint32(buffer, offset, declId); // decl_id
836     offset += uint32_t_size;
837     WriteUint64(buffer, offset, timestamp); // Timestamp
838     offset += uint64_t_size;
839     WriteBytes(buffer, offset, &threadId, threadId_size); // Thread id
840     offset += threadId_size;
841     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
842     offset += uint64_t_size;
843     // Update the number of bytes written
844     numberOfBytesWritten = timelineEventDataLength;
845
846     return TimelinePacketStatus::Ok;
847 }
848
849 std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
850 {
851     std::stringstream outputStream, centrePadding;
852     int padding = spacingWidth - static_cast<int>(stringToPass.size());
853
854     for (int i = 0; i < padding / 2; ++i)
855     {
856         centrePadding << " ";
857     }
858
859     outputStream << centrePadding.str() << stringToPass << centrePadding.str();
860
861     if (padding > 0 && padding %2 != 0)
862     {
863         outputStream << " ";
864     }
865
866     return outputStream.str();
867 }
868
869 void PrintDeviceDetails(const std::pair<const unsigned short, std::unique_ptr<Device>>& devicePair)
870 {
871     std::string body;
872
873     body.append(CentreAlignFormatting(devicePair.second->m_Name, 20));
874     body.append(" | ");
875     body.append(CentreAlignFormatting(std::to_string(devicePair.first), 13));
876     body.append(" | ");
877     body.append(CentreAlignFormatting(std::to_string(devicePair.second->m_Cores), 10));
878     body.append("\n");
879
880     std::cout << std::string(body.size(), '-') << "\n";
881     std::cout<< body;
882 }
883
884 void PrintCounterSetDetails(const std::pair<const unsigned short, std::unique_ptr<CounterSet>>& counterSetPair)
885 {
886     std::string body;
887
888     body.append(CentreAlignFormatting(counterSetPair.second->m_Name, 20));
889     body.append(" | ");
890     body.append(CentreAlignFormatting(std::to_string(counterSetPair.first), 13));
891     body.append(" | ");
892     body.append(CentreAlignFormatting(std::to_string(counterSetPair.second->m_Count), 10));
893     body.append("\n");
894
895     std::cout << std::string(body.size(), '-') << "\n";
896
897     std::cout<< body;
898 }
899
900 void PrintCounterDetails(std::shared_ptr<Counter>& counter)
901 {
902     std::string body;
903
904     body.append(CentreAlignFormatting(counter->m_Name, 20));
905     body.append(" | ");
906     body.append(CentreAlignFormatting(counter->m_Description, 50));
907     body.append(" | ");
908     body.append(CentreAlignFormatting(counter->m_Units, 14));
909     body.append(" | ");
910     body.append(CentreAlignFormatting(std::to_string(counter->m_Uid), 6));
911     body.append(" | ");
912     body.append(CentreAlignFormatting(std::to_string(counter->m_MaxCounterUid), 10));
913     body.append(" | ");
914     body.append(CentreAlignFormatting(std::to_string(counter->m_Class), 8));
915     body.append(" | ");
916     body.append(CentreAlignFormatting(std::to_string(counter->m_Interpolation), 14));
917     body.append(" | ");
918     body.append(CentreAlignFormatting(std::to_string(counter->m_Multiplier), 20));
919     body.append(" | ");
920     body.append(CentreAlignFormatting(std::to_string(counter->m_CounterSetUid), 16));
921     body.append(" | ");
922     body.append(CentreAlignFormatting(std::to_string(counter->m_DeviceUid), 14));
923
924     body.append("\n");
925
926     std::cout << std::string(body.size(), '-') << "\n";
927
928     std::cout << body;
929 }
930
931 void PrintCategoryDetails(const std::unique_ptr<Category>& category,
932                           std::unordered_map<unsigned short, std::shared_ptr<Counter>> counterMap)
933 {
934     std::string categoryBody;
935     std::string categoryHeader;
936
937     categoryHeader.append(CentreAlignFormatting("Name", 20));
938     categoryHeader.append(" | ");
939     categoryHeader.append(CentreAlignFormatting("Event Count", 14));
940     categoryHeader.append("\n");
941
942     categoryBody.append(CentreAlignFormatting(category->m_Name, 20));
943     categoryBody.append(" | ");
944     categoryBody.append(CentreAlignFormatting(std::to_string(category->m_Counters.size()), 14));
945
946     std::cout << "\n" << "\n";
947     std::cout << CentreAlignFormatting("CATEGORY", static_cast<int>(categoryHeader.size()));
948     std::cout << "\n";
949     std::cout << std::string(categoryHeader.size(), '=') << "\n";
950
951     std::cout << categoryHeader;
952
953     std::cout << std::string(categoryBody.size(), '-') << "\n";
954
955     std::cout << categoryBody;
956
957     std::string counterHeader;
958
959     counterHeader.append(CentreAlignFormatting("Counter Name", 20));
960     counterHeader.append(" | ");
961     counterHeader.append(CentreAlignFormatting("Description", 50));
962     counterHeader.append(" | ");
963     counterHeader.append(CentreAlignFormatting("Units", 14));
964     counterHeader.append(" | ");
965     counterHeader.append(CentreAlignFormatting("UID", 6));
966     counterHeader.append(" | ");
967     counterHeader.append(CentreAlignFormatting("Max UID", 10));
968     counterHeader.append(" | ");
969     counterHeader.append(CentreAlignFormatting("Class", 8));
970     counterHeader.append(" | ");
971     counterHeader.append(CentreAlignFormatting("Interpolation", 14));
972     counterHeader.append(" | ");
973     counterHeader.append(CentreAlignFormatting("Multiplier", 20));
974     counterHeader.append(" | ");
975     counterHeader.append(CentreAlignFormatting("Counter set UID", 16));
976     counterHeader.append(" | ");
977     counterHeader.append(CentreAlignFormatting("Device UID", 14));
978     counterHeader.append("\n");
979
980     std::cout << "\n" << "\n";
981     std::cout << CentreAlignFormatting("EVENTS IN CATEGORY: " + category->m_Name,
982                                        static_cast<int>(counterHeader.size()));
983     std::cout << "\n";
984     std::cout << std::string(counterHeader.size(), '=') << "\n";
985     std::cout << counterHeader;
986     for (auto& it: category->m_Counters) {
987         auto search = counterMap.find(it);
988         if(search != counterMap.end()) {
989             PrintCounterDetails(search->second);
990         }
991     }
992 }
993
994 void PrintCounterDirectory(ICounterDirectory& counterDirectory)
995 {
996     std::string devicesHeader;
997
998     devicesHeader.append(CentreAlignFormatting("Device name", 20));
999     devicesHeader.append(" | ");
1000     devicesHeader.append(CentreAlignFormatting("UID", 13));
1001     devicesHeader.append(" | ");
1002     devicesHeader.append(CentreAlignFormatting("Cores", 10));
1003     devicesHeader.append("\n");
1004
1005     std::cout << "\n" << "\n";
1006     std::cout << CentreAlignFormatting("DEVICES", static_cast<int>(devicesHeader.size()));
1007     std::cout << "\n";
1008     std::cout << std::string(devicesHeader.size(), '=') << "\n";
1009     std::cout << devicesHeader;
1010     for (auto& it: counterDirectory.GetDevices()) {
1011         PrintDeviceDetails(it);
1012     }
1013
1014     std::string counterSetHeader;
1015
1016     counterSetHeader.append(CentreAlignFormatting("Counter set name", 20));
1017     counterSetHeader.append(" | ");
1018     counterSetHeader.append(CentreAlignFormatting("UID", 13));
1019     counterSetHeader.append(" | ");
1020     counterSetHeader.append(CentreAlignFormatting("Count", 10));
1021     counterSetHeader.append("\n");
1022
1023     std::cout << "\n" << "\n";
1024     std::cout << CentreAlignFormatting("COUNTER SETS", static_cast<int>(counterSetHeader.size()));
1025     std::cout << "\n";
1026     std::cout << std::string(counterSetHeader.size(), '=') << "\n";
1027
1028     std::cout << counterSetHeader;
1029
1030     for (auto& it: counterDirectory.GetCounterSets()) {
1031         PrintCounterSetDetails(it);
1032     }
1033
1034     auto counters = counterDirectory.GetCounters();
1035     for (auto& it: counterDirectory.GetCategories()) {
1036         PrintCategoryDetails(it, counters);
1037     }
1038     std::cout << "\n";
1039 }
1040
1041 uint64_t GetTimestamp()
1042 {
1043 #if USE_CLOCK_MONOTONIC_RAW
1044     using clock = MonotonicClockRaw;
1045 #else
1046     using clock = std::chrono::steady_clock;
1047 #endif
1048
1049     // Take a timestamp
1050     auto timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(clock::now().time_since_epoch());
1051
1052     return static_cast<uint64_t>(timestamp.count());
1053 }
1054
1055 } // namespace profiling
1056
1057 } // namespace armnn
1058
1059 namespace std
1060 {
1061
1062 bool operator==(const std::vector<uint8_t>& left, std::thread::id right)
1063 {
1064     return std::memcmp(left.data(), &right, left.size()) == 0;
1065 }
1066
1067 } // namespace std