IVGCVSW-4454 Remove the CounterSet and Device fields from Category
[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 <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
454 TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid,
455                                                     const std::string& label,
456                                                     unsigned char* buffer,
457                                                     unsigned int bufferSize,
458                                                     unsigned int& numberOfBytesWritten)
459 {
460     // Initialize the output value
461     numberOfBytesWritten = 0;
462
463     // Check that the given buffer is valid
464     if (buffer == nullptr || bufferSize == 0)
465     {
466         return TimelinePacketStatus::BufferExhaustion;
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     {
478         return TimelinePacketStatus::Error;
479     }
480
481     // Calculate the size of the SWTrace string label (in bytes)
482     unsigned int swTraceLabelSize = boost::numeric_cast<unsigned int>(swTraceLabel.size()) * uint32_t_size;
483
484     // Calculate the length of the data (in bytes)
485     unsigned int timelineLabelPacketDataLength = uint32_t_size +   // decl_Id
486                                                  uint64_t_size +   // Profiling GUID
487                                                  swTraceLabelSize; // Label
488
489     // Calculate the timeline binary packet size (in bytes)
490     unsigned int timelineLabelPacketSize = 2 * uint32_t_size +            // Header (2 words)
491                                            timelineLabelPacketDataLength; // decl_Id + Profiling GUID + label
492
493     // Check whether the timeline binary packet fits in the given buffer
494     if (timelineLabelPacketSize > bufferSize)
495     {
496         return TimelinePacketStatus::BufferExhaustion;
497     }
498
499     // Create packet header
500     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineLabelPacketDataLength);
501
502     // Initialize the offset for writing in the buffer
503     unsigned int offset = 0;
504
505     // Write the timeline binary packet header to the buffer
506     WriteUint32(buffer, offset, packetHeader.first);
507     offset += uint32_t_size;
508     WriteUint32(buffer, offset, packetHeader.second);
509     offset += uint32_t_size;
510
511     // Write decl_Id to the buffer
512     WriteUint32(buffer, offset, 0u);
513     offset += uint32_t_size;
514
515     // Write the timeline binary packet payload to the buffer
516     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
517     offset += uint64_t_size;
518     for (uint32_t swTraceLabelWord : swTraceLabel)
519     {
520         WriteUint32(buffer, offset, swTraceLabelWord); // Label
521         offset += uint32_t_size;
522     }
523
524     // Update the number of bytes written
525     numberOfBytesWritten = timelineLabelPacketSize;
526
527     return TimelinePacketStatus::Ok;
528 }
529
530 TimelinePacketStatus WriteTimelineEntityBinaryPacket(uint64_t profilingGuid,
531                                                      unsigned char* buffer,
532                                                      unsigned int bufferSize,
533                                                      unsigned int& numberOfBytesWritten)
534 {
535     // Initialize the output value
536     numberOfBytesWritten = 0;
537
538     // Check that the given buffer is valid
539     if (buffer == nullptr || bufferSize == 0)
540     {
541         return TimelinePacketStatus::BufferExhaustion;
542     }
543
544     // Utils
545     unsigned int uint32_t_size = sizeof(uint32_t);
546     unsigned int uint64_t_size = sizeof(uint64_t);
547
548     // Calculate the length of the data (in bytes)
549     unsigned int timelineEntityPacketDataLength = uint32_t_size + uint64_t_size;  // decl_id + Profiling GUID
550
551
552     // Calculate the timeline binary packet size (in bytes)
553     unsigned int timelineEntityPacketSize = 2 * uint32_t_size +             // Header (2 words)
554                                             timelineEntityPacketDataLength; // Profiling GUID
555
556     // Check whether the timeline binary packet fits in the given buffer
557     if (timelineEntityPacketSize > bufferSize)
558     {
559         return TimelinePacketStatus::BufferExhaustion;
560     }
561
562     // Create packet header
563     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEntityPacketDataLength);
564
565     // Initialize the offset for writing in the buffer
566     unsigned int offset = 0;
567
568     // Write the timeline binary packet header to the buffer
569     WriteUint32(buffer, offset, packetHeader.first);
570     offset += uint32_t_size;
571     WriteUint32(buffer, offset, packetHeader.second);
572     offset += uint32_t_size;
573
574     // Write the decl_Id to the buffer
575     WriteUint32(buffer, offset, 1u);
576     offset += uint32_t_size;
577
578     // Write the timeline binary packet payload to the buffer
579     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
580
581     // Update the number of bytes written
582     numberOfBytesWritten = timelineEntityPacketSize;
583
584     return TimelinePacketStatus::Ok;
585 }
586
587 TimelinePacketStatus WriteTimelineRelationshipBinaryPacket(ProfilingRelationshipType relationshipType,
588                                                            uint64_t relationshipGuid,
589                                                            uint64_t headGuid,
590                                                            uint64_t tailGuid,
591                                                            unsigned char* buffer,
592                                                            unsigned int bufferSize,
593                                                            unsigned int& numberOfBytesWritten)
594 {
595     // Initialize the output value
596     numberOfBytesWritten = 0;
597
598     // Check that the given buffer is valid
599     if (buffer == nullptr || bufferSize == 0)
600     {
601         return TimelinePacketStatus::BufferExhaustion;
602     }
603
604     // Utils
605     unsigned int uint32_t_size = sizeof(uint32_t);
606     unsigned int uint64_t_size = sizeof(uint64_t);
607
608     // Calculate the length of the data (in bytes)
609     unsigned int timelineRelationshipPacketDataLength = uint32_t_size * 2 + // decl_id + Relationship Type
610                                                         uint64_t_size * 3; // Relationship GUID + Head GUID + tail GUID
611
612     // Calculate the timeline binary packet size (in bytes)
613     unsigned int timelineRelationshipPacketSize = 2 * uint32_t_size + // Header (2 words)
614                                                   timelineRelationshipPacketDataLength;
615
616     // Check whether the timeline binary packet fits in the given buffer
617     if (timelineRelationshipPacketSize > bufferSize)
618     {
619         return TimelinePacketStatus::BufferExhaustion;
620     }
621
622     // Create packet header
623     uint32_t dataLength = boost::numeric_cast<uint32_t>(timelineRelationshipPacketDataLength);
624     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(dataLength);
625
626     // Initialize the offset for writing in the buffer
627     unsigned int offset = 0;
628
629     // Write the timeline binary packet header to the buffer
630     WriteUint32(buffer, offset, packetHeader.first);
631     offset += uint32_t_size;
632     WriteUint32(buffer, offset, packetHeader.second);
633     offset += uint32_t_size;
634
635     uint32_t relationshipTypeUint = 0;
636
637     switch (relationshipType)
638     {
639         case ProfilingRelationshipType::RetentionLink:
640             relationshipTypeUint = 0;
641             break;
642         case ProfilingRelationshipType::ExecutionLink:
643             relationshipTypeUint = 1;
644             break;
645         case ProfilingRelationshipType::DataLink:
646             relationshipTypeUint = 2;
647             break;
648         case ProfilingRelationshipType::LabelLink:
649             relationshipTypeUint = 3;
650             break;
651         default:
652             throw InvalidArgumentException("Unknown relationship type given.");
653     }
654
655     // Write the timeline binary packet payload to the buffer
656     // decl_id of the timeline message
657     uint32_t declId = 3;
658     WriteUint32(buffer, offset, declId); // decl_id
659     offset += uint32_t_size;
660     WriteUint32(buffer, offset, relationshipTypeUint); // Relationship Type
661     offset += uint32_t_size;
662     WriteUint64(buffer, offset, relationshipGuid); // GUID of this relationship
663     offset += uint64_t_size;
664     WriteUint64(buffer, offset, headGuid); // head of relationship GUID
665     offset += uint64_t_size;
666     WriteUint64(buffer, offset, tailGuid); // tail of relationship GUID
667
668     // Update the number of bytes written
669     numberOfBytesWritten = timelineRelationshipPacketSize;
670
671     return TimelinePacketStatus::Ok;
672 }
673
674 TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char* buffer,
675                                                           unsigned int bufferSize,
676                                                           unsigned int& numberOfBytesWritten)
677 {
678     // Initialize the output value
679     numberOfBytesWritten = 0;
680
681     // Check that the given buffer is valid
682     if (buffer == nullptr || bufferSize == 0)
683     {
684         return TimelinePacketStatus::BufferExhaustion;
685     }
686
687     // Utils
688     unsigned int uint8_t_size  = sizeof(uint8_t);
689     unsigned int uint32_t_size = sizeof(uint32_t);
690     unsigned int uint64_t_size = sizeof(uint64_t);
691     unsigned int threadId_size = sizeof(std::thread::id);
692
693     // The payload/data of the packet consists of swtrace event definitions encoded according
694     // to the swtrace directory specification. The messages being the five defined below:
695     //
696     // |  decl_id  |     decl_name       |      ui_name          |  arg_types  |            arg_names                |
697     // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
698     // |    0      |   declareLabel      |   declare label       |    ps       |  guid,value                         |
699     // |    1      |   declareEntity     |   declare entity      |    p        |  guid                               |
700     // |    2      | declareEventClass   |  declare event class  |    p        |  guid                               |
701     // |    3      | declareRelationship | declare relationship  |    Ippp     |  relationshipType,relationshipGuid, |
702     // |           |                     |                       |             |  headGuid,tailGuid                  |
703     // |    4      |   declareEvent      |   declare event       |    @tp      |  timestamp,threadId,eventGuid       |
704     std::vector<std::vector<std::string>> timelineDirectoryMessages
705     {
706         { "0", "declareLabel", "declare label", "ps", "guid,value" },
707         { "1", "declareEntity", "declare entity", "p", "guid" },
708         { "2", "declareEventClass", "declare event class", "p", "guid" },
709         { "3", "declareRelationship", "declare relationship", "Ippp",
710           "relationshipType,relationshipGuid,headGuid,tailGuid" },
711         { "4", "declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid" }
712     };
713
714     // Build the message declarations
715     std::vector<uint32_t> swTraceBuffer;
716     for (const auto& directoryComponent : timelineDirectoryMessages)
717     {
718         // decl_id
719         uint32_t declId = 0;
720         try
721         {
722             declId = boost::numeric_cast<uint32_t>(std::stoul(directoryComponent[0]));
723         }
724         catch (const std::exception&)
725         {
726             return TimelinePacketStatus::Error;
727         }
728         swTraceBuffer.push_back(declId);
729
730         bool result = true;
731         result &= ConvertDirectoryComponent<SwTraceNameCharPolicy>(directoryComponent[1], swTraceBuffer); // decl_name
732         result &= ConvertDirectoryComponent<SwTraceCharPolicy>    (directoryComponent[2], swTraceBuffer); // ui_name
733         result &= ConvertDirectoryComponent<SwTraceTypeCharPolicy>(directoryComponent[3], swTraceBuffer); // arg_types
734         result &= ConvertDirectoryComponent<SwTraceCharPolicy>    (directoryComponent[4], swTraceBuffer); // arg_names
735         if (!result)
736         {
737             return TimelinePacketStatus::Error;
738         }
739     }
740
741     unsigned int dataLength = 3 * uint8_t_size +  // Stream header (3 bytes)
742                               boost::numeric_cast<unsigned int>(swTraceBuffer.size()) *
743                                   uint32_t_size; // Trace directory (5 messages)
744
745     // Calculate the timeline directory binary packet size (in bytes)
746     unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
747                                                dataLength;         // Payload
748
749     // Check whether the timeline directory binary packet fits in the given buffer
750     if (timelineDirectoryPacketSize > bufferSize)
751     {
752         return TimelinePacketStatus::BufferExhaustion;
753     }
754
755     // Create packet header
756     auto packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, boost::numeric_cast<uint32_t>(dataLength));
757
758     // Initialize the offset for writing in the buffer
759     unsigned int offset = 0;
760
761     // Write the timeline binary packet header to the buffer
762     WriteUint32(buffer, offset, packetHeader.first);
763     offset += uint32_t_size;
764     WriteUint32(buffer, offset, packetHeader.second);
765     offset += uint32_t_size;
766
767     // Write the stream header
768     uint8_t streamVersion = 4;
769     uint8_t pointerBytes  = boost::numeric_cast<uint8_t>(uint64_t_size); // All GUIDs are uint64_t
770     uint8_t threadIdBytes = boost::numeric_cast<uint8_t>(threadId_size);
771     switch (threadIdBytes)
772     {
773     case 4: // Typically Windows and Android
774     case 8: // Typically Linux
775         break; // Valid values
776     default:
777         return TimelinePacketStatus::Error; // Invalid value
778     }
779     WriteUint8(buffer, offset, streamVersion);
780     offset += uint8_t_size;
781     WriteUint8(buffer, offset, pointerBytes);
782     offset += uint8_t_size;
783     WriteUint8(buffer, offset, threadIdBytes);
784     offset += uint8_t_size;
785
786     // Write the SWTrace directory
787     uint32_t numberOfDeclarations = boost::numeric_cast<uint32_t>(timelineDirectoryMessages.size());
788     WriteUint32(buffer, offset, numberOfDeclarations); // Number of declarations
789     offset += uint32_t_size;
790     for (uint32_t i : swTraceBuffer)
791     {
792         WriteUint32(buffer, offset, i); // Message declarations
793         offset += uint32_t_size;
794     }
795
796     // Update the number of bytes written
797     numberOfBytesWritten = timelineDirectoryPacketSize;
798
799     return TimelinePacketStatus::Ok;
800 }
801
802 TimelinePacketStatus WriteTimelineEventClassBinaryPacket(uint64_t profilingGuid,
803                                                          unsigned char* buffer,
804                                                          unsigned int bufferSize,
805                                                          unsigned int& numberOfBytesWritten)
806 {
807     // Initialize the output value
808     numberOfBytesWritten = 0;
809
810     // Check that the given buffer is valid
811     if (buffer == nullptr || bufferSize == 0)
812     {
813         return TimelinePacketStatus::BufferExhaustion;
814     }
815
816     // Utils
817     unsigned int uint32_t_size = sizeof(uint32_t);
818     unsigned int uint64_t_size = sizeof(uint64_t);
819
820     // decl_id of the timeline message
821     uint32_t declId = 2;
822
823     // Calculate the length of the data (in bytes)
824     unsigned int packetBodySize = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
825
826     // Calculate the timeline binary packet size (in bytes)
827     unsigned int packetSize = 2 * uint32_t_size + // Header (2 words)
828                               packetBodySize;     // Body
829
830     // Check whether the timeline binary packet fits in the given buffer
831     if (packetSize > bufferSize)
832     {
833         return TimelinePacketStatus::BufferExhaustion;
834     }
835
836     // Create packet header
837     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(packetBodySize);
838
839     // Initialize the offset for writing in the buffer
840     unsigned int offset = 0;
841
842     // Write the timeline binary packet header to the buffer
843     WriteUint32(buffer, offset, packetHeader.first);
844     offset += uint32_t_size;
845     WriteUint32(buffer, offset, packetHeader.second);
846     offset += uint32_t_size;
847
848     // Write the timeline binary packet payload to the buffer
849     WriteUint32(buffer, offset, declId);        // decl_id
850     offset += uint32_t_size;
851     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
852
853     // Update the number of bytes written
854     numberOfBytesWritten = packetSize;
855
856     return TimelinePacketStatus::Ok;
857 }
858
859 TimelinePacketStatus WriteTimelineEventBinaryPacket(uint64_t timestamp,
860                                                     std::thread::id threadId,
861                                                     uint64_t profilingGuid,
862                                                     unsigned char* buffer,
863                                                     unsigned int bufferSize,
864                                                     unsigned int& numberOfBytesWritten)
865 {
866     // Initialize the output value
867     numberOfBytesWritten = 0;
868
869     // Check that the given buffer is valid
870     if (buffer == nullptr || bufferSize == 0)
871     {
872         return TimelinePacketStatus::BufferExhaustion;
873     }
874
875     // Utils
876     unsigned int uint32_t_size = sizeof(uint32_t);
877     unsigned int uint64_t_size = sizeof(uint64_t);
878     unsigned int threadId_size = sizeof(std::thread::id);
879
880     // decl_id of the timeline message
881     uint32_t declId = 4;
882
883     // Calculate the length of the data (in bytes)
884     unsigned int timelineEventPacketDataLength = uint32_t_size + // decl_id
885                                                  uint64_t_size + // Timestamp
886                                                  threadId_size + // Thread id
887                                                  uint64_t_size;  // Profiling GUID
888
889     // Calculate the timeline binary packet size (in bytes)
890     unsigned int timelineEventPacketSize = 2 * uint32_t_size +            // Header (2 words)
891                                            timelineEventPacketDataLength; // Timestamp + thread id + profiling GUID
892
893     // Check whether the timeline binary packet fits in the given buffer
894     if (timelineEventPacketSize > bufferSize)
895     {
896         return TimelinePacketStatus::BufferExhaustion;
897     }
898
899     // Create packet header
900     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEventPacketDataLength);
901
902     // Initialize the offset for writing in the buffer
903     unsigned int offset = 0;
904
905     // Write the timeline binary packet header to the buffer
906     WriteUint32(buffer, offset, packetHeader.first);
907     offset += uint32_t_size;
908     WriteUint32(buffer, offset, packetHeader.second);
909     offset += uint32_t_size;
910
911     // Write the timeline binary packet payload to the buffer
912     WriteUint32(buffer, offset, declId); // decl_id
913     offset += uint32_t_size;
914     WriteUint64(buffer, offset, timestamp); // Timestamp
915     offset += uint64_t_size;
916     WriteBytes(buffer, offset, &threadId, threadId_size); // Thread id
917     offset += threadId_size;
918     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
919     offset += uint64_t_size;
920
921     // Update the number of bytes written
922     numberOfBytesWritten = timelineEventPacketSize;
923
924     return TimelinePacketStatus::Ok;
925 }
926
927 std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
928 {
929     std::stringstream outputStream, centrePadding;
930     int padding = spacingWidth - static_cast<int>(stringToPass.size());
931
932     for (int i = 0; i < padding / 2; ++i)
933     {
934         centrePadding << " ";
935     }
936
937     outputStream << centrePadding.str() << stringToPass << centrePadding.str();
938
939     if (padding > 0 && padding %2 != 0)
940     {
941         outputStream << " ";
942     }
943
944     return outputStream.str();
945 }
946
947 void PrintDeviceDetails(const std::pair<const unsigned short, std::unique_ptr<Device>>& devicePair)
948 {
949     std::string body;
950
951     body.append(CentreAlignFormatting(devicePair.second->m_Name, 20));
952     body.append(" | ");
953     body.append(CentreAlignFormatting(std::to_string(devicePair.first), 13));
954     body.append(" | ");
955     body.append(CentreAlignFormatting(std::to_string(devicePair.second->m_Cores), 10));
956     body.append("\n");
957
958     std::cout << std::string(body.size(), '-') << "\n";
959     std::cout<< body;
960 }
961
962 void PrintCounterSetDetails(const std::pair<const unsigned short, std::unique_ptr<CounterSet>>& counterSetPair)
963 {
964     std::string body;
965
966     body.append(CentreAlignFormatting(counterSetPair.second->m_Name, 20));
967     body.append(" | ");
968     body.append(CentreAlignFormatting(std::to_string(counterSetPair.first), 13));
969     body.append(" | ");
970     body.append(CentreAlignFormatting(std::to_string(counterSetPair.second->m_Count), 10));
971     body.append("\n");
972
973     std::cout << std::string(body.size(), '-') << "\n";
974
975     std::cout<< body;
976 }
977
978 void PrintCounterDetails(std::shared_ptr<Counter>& counter)
979 {
980     std::string body;
981
982     body.append(CentreAlignFormatting(counter->m_Name, 20));
983     body.append(" | ");
984     body.append(CentreAlignFormatting(counter->m_Description, 50));
985     body.append(" | ");
986     body.append(CentreAlignFormatting(counter->m_Units, 14));
987     body.append(" | ");
988     body.append(CentreAlignFormatting(std::to_string(counter->m_Uid), 6));
989     body.append(" | ");
990     body.append(CentreAlignFormatting(std::to_string(counter->m_MaxCounterUid), 10));
991     body.append(" | ");
992     body.append(CentreAlignFormatting(std::to_string(counter->m_Class), 8));
993     body.append(" | ");
994     body.append(CentreAlignFormatting(std::to_string(counter->m_Interpolation), 14));
995     body.append(" | ");
996     body.append(CentreAlignFormatting(std::to_string(counter->m_Multiplier), 20));
997     body.append(" | ");
998     body.append(CentreAlignFormatting(std::to_string(counter->m_CounterSetUid), 16));
999     body.append(" | ");
1000     body.append(CentreAlignFormatting(std::to_string(counter->m_DeviceUid), 14));
1001
1002     body.append("\n");
1003
1004     std::cout << std::string(body.size(), '-') << "\n";
1005
1006     std::cout << body;
1007 }
1008
1009 void PrintCategoryDetails(const std::unique_ptr<Category>& category,
1010                           std::unordered_map<unsigned short, std::shared_ptr<Counter>> counterMap)
1011 {
1012     std::string categoryBody;
1013     std::string categoryHeader;
1014
1015     categoryHeader.append(CentreAlignFormatting("Name", 20));
1016     categoryHeader.append(" | ");
1017     categoryHeader.append(CentreAlignFormatting("Event Count", 14));
1018     categoryHeader.append("\n");
1019
1020     categoryBody.append(CentreAlignFormatting(category->m_Name, 20));
1021     categoryBody.append(" | ");
1022     categoryBody.append(CentreAlignFormatting(std::to_string(category->m_Counters.size()), 14));
1023
1024     std::cout << "\n" << "\n";
1025     std::cout << CentreAlignFormatting("CATEGORY", static_cast<int>(categoryHeader.size()));
1026     std::cout << "\n";
1027     std::cout << std::string(categoryHeader.size(), '=') << "\n";
1028
1029     std::cout << categoryHeader;
1030
1031     std::cout << std::string(categoryBody.size(), '-') << "\n";
1032
1033     std::cout << categoryBody;
1034
1035     std::string counterHeader;
1036
1037     counterHeader.append(CentreAlignFormatting("Counter Name", 20));
1038     counterHeader.append(" | ");
1039     counterHeader.append(CentreAlignFormatting("Description", 50));
1040     counterHeader.append(" | ");
1041     counterHeader.append(CentreAlignFormatting("Units", 14));
1042     counterHeader.append(" | ");
1043     counterHeader.append(CentreAlignFormatting("UID", 6));
1044     counterHeader.append(" | ");
1045     counterHeader.append(CentreAlignFormatting("Max UID", 10));
1046     counterHeader.append(" | ");
1047     counterHeader.append(CentreAlignFormatting("Class", 8));
1048     counterHeader.append(" | ");
1049     counterHeader.append(CentreAlignFormatting("Interpolation", 14));
1050     counterHeader.append(" | ");
1051     counterHeader.append(CentreAlignFormatting("Multiplier", 20));
1052     counterHeader.append(" | ");
1053     counterHeader.append(CentreAlignFormatting("Counter set UID", 16));
1054     counterHeader.append(" | ");
1055     counterHeader.append(CentreAlignFormatting("Device UID", 14));
1056     counterHeader.append("\n");
1057
1058     std::cout << "\n" << "\n";
1059     std::cout << CentreAlignFormatting("EVENTS IN CATEGORY: " + category->m_Name,
1060                                        static_cast<int>(counterHeader.size()));
1061     std::cout << "\n";
1062     std::cout << std::string(counterHeader.size(), '=') << "\n";
1063     std::cout << counterHeader;
1064     for (auto& it: category->m_Counters) {
1065         auto search = counterMap.find(it);
1066         if(search != counterMap.end()) {
1067             PrintCounterDetails(search->second);
1068         }
1069     }
1070 }
1071
1072 void PrintCounterDirectory(ICounterDirectory& counterDirectory)
1073 {
1074     std::string devicesHeader;
1075
1076     devicesHeader.append(CentreAlignFormatting("Device name", 20));
1077     devicesHeader.append(" | ");
1078     devicesHeader.append(CentreAlignFormatting("UID", 13));
1079     devicesHeader.append(" | ");
1080     devicesHeader.append(CentreAlignFormatting("Cores", 10));
1081     devicesHeader.append("\n");
1082
1083     std::cout << "\n" << "\n";
1084     std::cout << CentreAlignFormatting("DEVICES", static_cast<int>(devicesHeader.size()));
1085     std::cout << "\n";
1086     std::cout << std::string(devicesHeader.size(), '=') << "\n";
1087     std::cout << devicesHeader;
1088     for (auto& it: counterDirectory.GetDevices()) {
1089         PrintDeviceDetails(it);
1090     }
1091
1092     std::string counterSetHeader;
1093
1094     counterSetHeader.append(CentreAlignFormatting("Counter set name", 20));
1095     counterSetHeader.append(" | ");
1096     counterSetHeader.append(CentreAlignFormatting("UID", 13));
1097     counterSetHeader.append(" | ");
1098     counterSetHeader.append(CentreAlignFormatting("Count", 10));
1099     counterSetHeader.append("\n");
1100
1101     std::cout << "\n" << "\n";
1102     std::cout << CentreAlignFormatting("COUNTER SETS", static_cast<int>(counterSetHeader.size()));
1103     std::cout << "\n";
1104     std::cout << std::string(counterSetHeader.size(), '=') << "\n";
1105
1106     std::cout << counterSetHeader;
1107
1108     for (auto& it: counterDirectory.GetCounterSets()) {
1109         PrintCounterSetDetails(it);
1110     }
1111
1112     auto counters = counterDirectory.GetCounters();
1113     for (auto& it: counterDirectory.GetCategories()) {
1114         PrintCategoryDetails(it, counters);
1115     }
1116     std::cout << "\n";
1117 }
1118
1119 uint64_t GetTimestamp()
1120 {
1121 #if USE_CLOCK_MONOTONIC_RAW
1122     using clock = MonotonicClockRaw;
1123 #else
1124     using clock = std::chrono::steady_clock;
1125 #endif
1126
1127     // Take a timestamp
1128     auto timestamp = clock::now();
1129
1130     return static_cast<uint64_t>(timestamp.time_since_epoch().count());
1131 }
1132
1133 } // namespace profiling
1134
1135 } // namespace armnn
1136
1137 namespace std
1138 {
1139
1140 bool operator==(const std::vector<uint8_t>& left, std::thread::id right)
1141 {
1142     return std::memcmp(left.data(), &right, left.size()) == 0;
1143 }
1144
1145 } // namespace std