IVGCVSW-4065 Use platform-specific thread id size in Timeline packets
[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 #include <armnn/Conversion.hpp>
10
11 #include <boost/assert.hpp>
12
13 #include <fstream>
14 #include <limits>
15
16 namespace armnn
17 {
18
19 namespace profiling
20 {
21
22 namespace
23 {
24
25 void ThrowIfCantGenerateNextUid(uint16_t uid, uint16_t cores = 0)
26 {
27     // Check that it is possible to generate the next UID without causing an overflow
28     switch (cores)
29     {
30     case 0:
31     case 1:
32         // Number of cores not specified or set to 1 (a value of zero indicates the device is not capable of
33         // running multiple parallel workloads and will not provide multiple streams of data for each event)
34         if (uid == std::numeric_limits<uint16_t>::max())
35         {
36             throw RuntimeException("Generating the next UID for profiling would result in an overflow");
37         }
38         break;
39     default: // cores > 1
40         // Multiple cores available, as max_counter_uid has to be set to: counter_uid + cores - 1, the maximum
41         // allowed value for a counter UID is consequently: uint16_t_max - cores + 1
42         if (uid >= std::numeric_limits<uint16_t>::max() - cores + 1)
43         {
44             throw RuntimeException("Generating the next UID for profiling would result in an overflow");
45         }
46         break;
47     }
48 }
49
50 } // Anonymous namespace
51
52 uint16_t GetNextUid(bool peekOnly)
53 {
54     // The UID used for profiling objects and events. The first valid UID is 1, as 0 is a reserved value
55     static uint16_t uid = 1;
56
57     // Check that it is possible to generate the next UID without causing an overflow (throws in case of error)
58     ThrowIfCantGenerateNextUid(uid);
59
60     if (peekOnly)
61     {
62         // Peek only
63         return uid;
64     }
65     else
66     {
67         // Get the next UID
68         return uid++;
69     }
70 }
71
72 std::vector<uint16_t> GetNextCounterUids(uint16_t cores)
73 {
74     // The UID used for counters only. The first valid UID is 0
75     static uint16_t counterUid = 0;
76
77     // Check that it is possible to generate the next counter UID without causing an overflow (throws in case of error)
78     ThrowIfCantGenerateNextUid(counterUid, cores);
79
80     // Get the next counter UIDs
81     size_t counterUidsSize = cores == 0 ? 1 : cores;
82     std::vector<uint16_t> counterUids(counterUidsSize, 0);
83     for (size_t i = 0; i < counterUidsSize; i++)
84     {
85         counterUids[i] = counterUid++;
86     }
87     return counterUids;
88 }
89
90 void WriteBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset,  const void* value, unsigned int valueSize)
91 {
92     BOOST_ASSERT(packetBuffer);
93
94     WriteBytes(packetBuffer->GetWritableData(), offset, value, valueSize);
95 }
96
97 void WriteUint64(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint64_t value)
98 {
99     BOOST_ASSERT(packetBuffer);
100
101     WriteUint64(packetBuffer->GetWritableData(), offset, value);
102 }
103
104 void WriteUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint32_t value)
105 {
106     BOOST_ASSERT(packetBuffer);
107
108     WriteUint32(packetBuffer->GetWritableData(), offset, value);
109 }
110
111 void WriteUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint16_t value)
112 {
113     BOOST_ASSERT(packetBuffer);
114
115     WriteUint16(packetBuffer->GetWritableData(), offset, value);
116 }
117
118 void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize)
119 {
120     BOOST_ASSERT(buffer);
121     BOOST_ASSERT(value);
122
123     for (unsigned int i = 0; i < valueSize; i++, offset++)
124     {
125         buffer[offset] = *(reinterpret_cast<const unsigned char*>(value) + i);
126     }
127 }
128
129 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
130 {
131     BOOST_ASSERT(buffer);
132
133     buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
134     buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
135     buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
136     buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
137     buffer[offset + 4] = static_cast<unsigned char>((value >> 32) & 0xFF);
138     buffer[offset + 5] = static_cast<unsigned char>((value >> 40) & 0xFF);
139     buffer[offset + 6] = static_cast<unsigned char>((value >> 48) & 0xFF);
140     buffer[offset + 7] = static_cast<unsigned char>((value >> 56) & 0xFF);
141 }
142
143 void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value)
144 {
145     BOOST_ASSERT(buffer);
146
147     buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
148     buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
149     buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
150     buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
151 }
152
153 void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value)
154 {
155     BOOST_ASSERT(buffer);
156
157     buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
158     buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
159 }
160
161 void ReadBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
162 {
163     BOOST_ASSERT(packetBuffer);
164
165     ReadBytes(packetBuffer->GetReadableData(), offset, valueSize, outValue);
166 }
167
168 uint64_t ReadUint64(const IPacketBufferPtr& packetBuffer, unsigned int offset)
169 {
170     BOOST_ASSERT(packetBuffer);
171
172     return ReadUint64(packetBuffer->GetReadableData(), offset);
173 }
174
175 uint32_t ReadUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset)
176 {
177     BOOST_ASSERT(packetBuffer);
178
179     return ReadUint32(packetBuffer->GetReadableData(), offset);
180 }
181
182 uint16_t ReadUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset)
183 {
184     BOOST_ASSERT(packetBuffer);
185
186     return ReadUint16(packetBuffer->GetReadableData(), offset);
187 }
188
189 uint8_t ReadUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset)
190 {
191     BOOST_ASSERT(packetBuffer);
192
193     return ReadUint8(packetBuffer->GetReadableData(), offset);
194 }
195
196 void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
197 {
198     BOOST_ASSERT(buffer);
199     BOOST_ASSERT(outValue);
200
201     for (unsigned int i = 0; i < valueSize; i++, offset++)
202     {
203         outValue[i] = static_cast<uint8_t>(buffer[offset]);
204     }
205 }
206
207 uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
208 {
209     BOOST_ASSERT(buffer);
210
211     uint64_t value = 0;
212     value  = static_cast<uint64_t>(buffer[offset]);
213     value |= static_cast<uint64_t>(buffer[offset + 1]) << 8;
214     value |= static_cast<uint64_t>(buffer[offset + 2]) << 16;
215     value |= static_cast<uint64_t>(buffer[offset + 3]) << 24;
216     value |= static_cast<uint64_t>(buffer[offset + 4]) << 32;
217     value |= static_cast<uint64_t>(buffer[offset + 5]) << 40;
218     value |= static_cast<uint64_t>(buffer[offset + 6]) << 48;
219     value |= static_cast<uint64_t>(buffer[offset + 7]) << 56;
220
221     return value;
222 }
223
224 uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset)
225 {
226     BOOST_ASSERT(buffer);
227
228     uint32_t value = 0;
229     value  = static_cast<uint32_t>(buffer[offset]);
230     value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
231     value |= static_cast<uint32_t>(buffer[offset + 2]) << 16;
232     value |= static_cast<uint32_t>(buffer[offset + 3]) << 24;
233     return value;
234 }
235
236 uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset)
237 {
238     BOOST_ASSERT(buffer);
239
240     uint32_t value = 0;
241     value  = static_cast<uint32_t>(buffer[offset]);
242     value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
243     return static_cast<uint16_t>(value);
244 }
245
246 uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset)
247 {
248     BOOST_ASSERT(buffer);
249
250     return buffer[offset];
251 }
252
253 std::string GetSoftwareInfo()
254 {
255     return std::string("ArmNN");
256 }
257
258 std::string GetHardwareVersion()
259 {
260     return std::string();
261 }
262
263 std::string GetSoftwareVersion()
264 {
265     std::string armnnVersion(ARMNN_VERSION);
266     std::string result = "Armnn " + armnnVersion.substr(2,2) + "." + armnnVersion.substr(4,2);
267     return result;
268 }
269
270 std::string GetProcessName()
271 {
272     std::ifstream comm("/proc/self/comm");
273     std::string name;
274     getline(comm, name);
275     return name;
276 }
277
278 /// Creates a timeline packet header
279 ///
280 /// \params
281 ///   packetFamiliy     Timeline Packet Family
282 ///   packetClass       Timeline Packet Class
283 ///   packetType        Timeline Packet Type
284 ///   streamId          Stream identifier
285 ///   seqeunceNumbered  When non-zero the 4 bytes following the header is a u32 sequence number
286 ///   dataLength        Unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
287 ///
288 /// \returns
289 ///   Pair of uint32_t containing word0 and word1 of the header
290 std::pair<uint32_t, uint32_t> CreateTimelinePacketHeader(uint32_t packetFamily,
291                                                          uint32_t packetClass,
292                                                          uint32_t packetType,
293                                                          uint32_t streamId,
294                                                          uint32_t sequenceNumbered,
295                                                          uint32_t dataLength)
296 {
297     // Packet header word 0:
298     // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
299     // 19:25 [7] packet_class: packet class
300     // 16:18 [3] packet_type: packet type
301     // 8:15  [8] reserved: all zeros
302     // 0:7   [8] stream_id: stream identifier
303     uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
304                                  ((packetClass  & 0x0000007F) << 19) |
305                                  ((packetType   & 0x00000007) << 16) |
306                                  ((streamId     & 0x00000007) <<  0);
307
308     // Packet header word 1:
309     // 25:31 [7]  reserved: all zeros
310     // 24    [1]  sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
311     // 0:23  [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
312     uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
313                                  ((dataLength       & 0x00FFFFFF) <<  0);
314
315     return std::make_pair(packetHeaderWord0, packetHeaderWord1);
316 }
317
318 // Calculate the actual length an SwString will be including the terminating null character
319 // padding to bring it to the next uint32_t boundary but minus the leading uint32_t encoding
320 // the size to allow the offset to be correctly updated when decoding a binary packet.
321 uint32_t CalculateSizeOfPaddedSwString(const std::string& str)
322 {
323     std::vector<uint32_t> swTraceString;
324     StringToSwTraceString<SwTraceCharPolicy>(str, swTraceString);
325     unsigned int uint32_t_size = sizeof(uint32_t);
326     uint32_t size = (boost::numeric_cast<uint32_t>(swTraceString.size()) - 1) * uint32_t_size;
327     return size;
328 }
329
330 // Read TimelineMessageDirectoryPacket from given IPacketBuffer and offset
331 SwTraceMessage ReadSwTraceMessage(const IPacketBufferPtr& packetBuffer, unsigned int& offset)
332 {
333     BOOST_ASSERT(packetBuffer);
334
335     unsigned int uint32_t_size = sizeof(uint32_t);
336
337     SwTraceMessage swTraceMessage;
338
339     // Read the decl_id
340     uint32_t readDeclId = ReadUint32(packetBuffer, offset);
341     swTraceMessage.id = readDeclId;
342
343     // SWTrace "namestring" format
344     // length of the string (first 4 bytes) + string + null terminator
345
346     // Check the decl_name
347     offset += uint32_t_size;
348     uint32_t swTraceDeclNameLength = ReadUint32(packetBuffer, offset);
349
350     offset += uint32_t_size;
351     std::vector<unsigned char> swTraceStringBuffer(swTraceDeclNameLength - 1);
352     std::memcpy(swTraceStringBuffer.data(),
353                 packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
354
355     swTraceMessage.name.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // name
356
357     // Check the ui_name
358     offset += CalculateSizeOfPaddedSwString(swTraceMessage.name);
359     uint32_t swTraceUINameLength = ReadUint32(packetBuffer, offset);
360
361     offset += uint32_t_size;
362     swTraceStringBuffer.resize(swTraceUINameLength - 1);
363     std::memcpy(swTraceStringBuffer.data(),
364                 packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
365
366     swTraceMessage.uiName.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // ui_name
367
368     // Check arg_types
369     offset += CalculateSizeOfPaddedSwString(swTraceMessage.uiName);
370     uint32_t swTraceArgTypesLength = ReadUint32(packetBuffer, offset);
371
372     offset += uint32_t_size;
373     swTraceStringBuffer.resize(swTraceArgTypesLength - 1);
374     std::memcpy(swTraceStringBuffer.data(),
375                 packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
376
377     swTraceMessage.argTypes.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // arg_types
378
379     std::string swTraceString(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
380
381     // Check arg_names
382     offset += CalculateSizeOfPaddedSwString(swTraceString);
383     uint32_t swTraceArgNamesLength = ReadUint32(packetBuffer, offset);
384
385     offset += uint32_t_size;
386     swTraceStringBuffer.resize(swTraceArgNamesLength - 1);
387     std::memcpy(swTraceStringBuffer.data(),
388                 packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
389
390     swTraceString.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
391     std::stringstream stringStream(swTraceString);
392     std::string argName;
393     while (std::getline(stringStream, argName, ','))
394     {
395         swTraceMessage.argNames.push_back(argName);
396     }
397
398     offset += CalculateSizeOfPaddedSwString(swTraceString);
399
400     return swTraceMessage;
401 }
402
403 /// Creates a packet header for the timeline messages:
404 /// * declareLabel
405 /// * declareEntity
406 /// * declareEventClass
407 /// * declareRelationship
408 /// * declareEvent
409 ///
410 /// \param
411 ///   dataLength The length of the message body in bytes
412 ///
413 /// \returns
414 ///   Pair of uint32_t containing word0 and word1 of the header
415 std::pair<uint32_t, uint32_t> CreateTimelineMessagePacketHeader(unsigned int dataLength)
416 {
417     return CreateTimelinePacketHeader(1,           // Packet family
418                                       0,           // Packet class
419                                       1,           // Packet type
420                                       0,           // Stream id
421                                       0,           // Sequence number
422                                       dataLength); // Data length
423 }
424
425 TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid,
426                                                     const std::string& label,
427                                                     unsigned char* buffer,
428                                                     unsigned int bufferSize,
429                                                     unsigned int& numberOfBytesWritten)
430 {
431     // Initialize the output value
432     numberOfBytesWritten = 0;
433
434     // Check that the given buffer is valid
435     if (buffer == nullptr || bufferSize == 0)
436     {
437         return TimelinePacketStatus::BufferExhaustion;
438     }
439
440     // Utils
441     unsigned int uint32_t_size = sizeof(uint32_t);
442     unsigned int uint64_t_size = sizeof(uint64_t);
443
444     // Convert the label into a SWTrace string
445     std::vector<uint32_t> swTraceLabel;
446     bool result = StringToSwTraceString<SwTraceCharPolicy>(label, swTraceLabel);
447     if (!result)
448     {
449         return TimelinePacketStatus::Error;
450     }
451
452     // Calculate the size of the SWTrace string label (in bytes)
453     unsigned int swTraceLabelSize = boost::numeric_cast<unsigned int>(swTraceLabel.size()) * uint32_t_size;
454
455     // Calculate the length of the data (in bytes)
456     unsigned int timelineLabelPacketDataLength = uint32_t_size +   // decl_Id
457                                                  uint64_t_size +   // Profiling GUID
458                                                  swTraceLabelSize; // Label
459
460     // Calculate the timeline binary packet size (in bytes)
461     unsigned int timelineLabelPacketSize = 2 * uint32_t_size +            // Header (2 words)
462                                            timelineLabelPacketDataLength; // decl_Id + Profiling GUID + label
463
464     // Check whether the timeline binary packet fits in the given buffer
465     if (timelineLabelPacketSize > bufferSize)
466     {
467         return TimelinePacketStatus::BufferExhaustion;
468     }
469
470     // Create packet header
471     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineLabelPacketDataLength);
472
473     // Initialize the offset for writing in the buffer
474     unsigned int offset = 0;
475
476     // Write the timeline binary packet header to the buffer
477     WriteUint32(buffer, offset, packetHeader.first);
478     offset += uint32_t_size;
479     WriteUint32(buffer, offset, packetHeader.second);
480     offset += uint32_t_size;
481
482     // Write decl_Id to the buffer
483     WriteUint32(buffer, offset, 0u);
484     offset += uint32_t_size;
485
486     // Write the timeline binary packet payload to the buffer
487     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
488     offset += uint64_t_size;
489     for (uint32_t swTraceLabelWord : swTraceLabel)
490     {
491         WriteUint32(buffer, offset, swTraceLabelWord); // Label
492         offset += uint32_t_size;
493     }
494
495     // Update the number of bytes written
496     numberOfBytesWritten = timelineLabelPacketSize;
497
498     return TimelinePacketStatus::Ok;
499 }
500
501 TimelinePacketStatus WriteTimelineEntityBinaryPacket(uint64_t profilingGuid,
502                                                      unsigned char* buffer,
503                                                      unsigned int bufferSize,
504                                                      unsigned int& numberOfBytesWritten)
505 {
506     // Initialize the output value
507     numberOfBytesWritten = 0;
508
509     // Check that the given buffer is valid
510     if (buffer == nullptr || bufferSize == 0)
511     {
512         return TimelinePacketStatus::BufferExhaustion;
513     }
514
515     // Utils
516     unsigned int uint32_t_size = sizeof(uint32_t);
517     unsigned int uint64_t_size = sizeof(uint64_t);
518
519     // Calculate the length of the data (in bytes)
520     unsigned int timelineEntityPacketDataLength = uint64_t_size;   // Profiling GUID
521
522
523     // Calculate the timeline binary packet size (in bytes)
524     unsigned int timelineEntityPacketSize = 2 * uint32_t_size +             // Header (2 words)
525                                             uint32_t_size +                 // decl_Id
526                                             timelineEntityPacketDataLength; // Profiling GUID
527
528     // Check whether the timeline binary packet fits in the given buffer
529     if (timelineEntityPacketSize > bufferSize)
530     {
531         return TimelinePacketStatus::BufferExhaustion;
532     }
533
534     // Create packet header
535     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEntityPacketDataLength);
536
537     // Initialize the offset for writing in the buffer
538     unsigned int offset = 0;
539
540     // Write the timeline binary packet header to the buffer
541     WriteUint32(buffer, offset, packetHeader.first);
542     offset += uint32_t_size;
543     WriteUint32(buffer, offset, packetHeader.second);
544     offset += uint32_t_size;
545
546     // Write the decl_Id to the buffer
547     WriteUint32(buffer, offset, 1u);
548     offset += uint32_t_size;
549
550     // Write the timeline binary packet payload to the buffer
551     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
552
553     // Update the number of bytes written
554     numberOfBytesWritten = timelineEntityPacketSize;
555
556     return TimelinePacketStatus::Ok;
557 }
558
559 TimelinePacketStatus WriteTimelineRelationshipBinaryPacket(ProfilingRelationshipType relationshipType,
560                                                            uint64_t relationshipGuid,
561                                                            uint64_t headGuid,
562                                                            uint64_t tailGuid,
563                                                            unsigned char* buffer,
564                                                            unsigned int bufferSize,
565                                                            unsigned int& numberOfBytesWritten)
566 {
567     // Initialize the output value
568     numberOfBytesWritten = 0;
569
570     // Check that the given buffer is valid
571     if (buffer == nullptr || bufferSize == 0)
572     {
573         return TimelinePacketStatus::BufferExhaustion;
574     }
575
576     // Utils
577     unsigned int uint32_t_size = sizeof(uint32_t);
578     unsigned int uint64_t_size = sizeof(uint64_t);
579
580     // Calculate the length of the data (in bytes)
581     unsigned int timelineRelationshipPacketDataLength = uint32_t_size * 2 + // decl_id + Relationship Type
582                                                         uint64_t_size * 3; // Relationship GUID + Head GUID + tail GUID
583
584     // Calculate the timeline binary packet size (in bytes)
585     unsigned int timelineRelationshipPacketSize = 2 * uint32_t_size + // Header (2 words)
586                                                   timelineRelationshipPacketDataLength;
587
588     // Check whether the timeline binary packet fits in the given buffer
589     if (timelineRelationshipPacketSize > bufferSize)
590     {
591         return TimelinePacketStatus::BufferExhaustion;
592     }
593
594     // Create packet header
595     uint32_t dataLength = boost::numeric_cast<uint32_t>(timelineRelationshipPacketDataLength);
596     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(dataLength);
597
598     // Initialize the offset for writing in the buffer
599     unsigned int offset = 0;
600
601     // Write the timeline binary packet header to the buffer
602     WriteUint32(buffer, offset, packetHeader.first);
603     offset += uint32_t_size;
604     WriteUint32(buffer, offset, packetHeader.second);
605     offset += uint32_t_size;
606
607     uint32_t relationshipTypeUint = 0;
608
609     switch (relationshipType)
610     {
611         case ProfilingRelationshipType::RetentionLink:
612             relationshipTypeUint = 0;
613             break;
614         case ProfilingRelationshipType::ExecutionLink:
615             relationshipTypeUint = 1;
616             break;
617         case ProfilingRelationshipType::DataLink:
618             relationshipTypeUint = 2;
619             break;
620         case ProfilingRelationshipType::LabelLink:
621             relationshipTypeUint = 3;
622             break;
623         default:
624             throw InvalidArgumentException("Unknown relationship type given.");
625     }
626
627     // Write the timeline binary packet payload to the buffer
628     // decl_id of the timeline message
629     uint32_t declId = 3;
630     WriteUint32(buffer, offset, declId); // decl_id
631     offset += uint32_t_size;
632     WriteUint32(buffer, offset, relationshipTypeUint); // Relationship Type
633     offset += uint32_t_size;
634     WriteUint64(buffer, offset, relationshipGuid); // GUID of this relationship
635     offset += uint64_t_size;
636     WriteUint64(buffer, offset, headGuid); // head of relationship GUID
637     offset += uint64_t_size;
638     WriteUint64(buffer, offset, tailGuid); // tail of relationship GUID
639
640     // Update the number of bytes written
641     numberOfBytesWritten = timelineRelationshipPacketSize;
642
643     return TimelinePacketStatus::Ok;
644 }
645
646 TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char* buffer,
647                                                           unsigned int bufferSize,
648                                                           unsigned int& numberOfBytesWritten)
649 {
650     // Initialize the output value
651     numberOfBytesWritten = 0;
652
653     // Check that the given buffer is valid
654     if (buffer == nullptr || bufferSize == 0)
655     {
656         return TimelinePacketStatus::BufferExhaustion;
657     }
658
659     // Utils
660     unsigned int uint32_t_size = sizeof(uint32_t);
661
662     // The payload/data of the packet consists of swtrace event definitions encoded according
663     // to the swtrace directory specification. The messages being the five defined below:
664     // |  decl_id  |  decl_name          |    ui_name            |  arg_types  |  arg_names                          |
665     // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
666     // |    0      |   declareLabel      |   declare label       |    ps       |  guid,value                         |
667     // |    1      |   declareEntity     |   declare entity      |    p        |  guid                               |
668     // |    2      | declareEventClass   |  declare event class  |    p        |  guid                               |
669     // |    3      | declareRelationship | declare relationship  |    Ippp     |  relationshipType,relationshipGuid, |
670     // |           |                     |                       |             |  headGuid,tailGuid                  |
671     // |    4      |   declareEvent      |   declare event       |    @tp      |  timestamp,threadId,eventGuid       |
672
673     std::vector<std::vector<std::string>> timelineDirectoryMessages
674     {
675         {"declareLabel", "declare label", "ps", "guid,value"},
676         {"declareEntity", "declare entity", "p", "guid"},
677         {"declareEventClass", "declare event class", "p", "guid"},
678         {"declareRelationship", "declare relationship", "Ippp", "relationshipType,relationshipGuid,headGuid,tailGuid"},
679         {"declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid"}
680     };
681
682     unsigned int messagesDataLength = 0u;
683     std::vector<std::vector<std::vector<uint32_t>>> swTraceTimelineDirectoryMessages;
684
685     for (const auto& timelineDirectoryMessage : timelineDirectoryMessages)
686     {
687         messagesDataLength += uint32_t_size; // decl_id
688
689         std::vector<std::vector<uint32_t>> swTraceStringsVector;
690         for (const auto& label : timelineDirectoryMessage)
691         {
692             std::vector<uint32_t> swTraceString;
693             bool result = StringToSwTraceString<SwTraceCharPolicy>(label, swTraceString);
694             if (!result)
695             {
696                 return TimelinePacketStatus::Error;
697             }
698
699             messagesDataLength += boost::numeric_cast<unsigned int>(swTraceString.size()) * uint32_t_size;
700             swTraceStringsVector.push_back(swTraceString);
701         }
702         swTraceTimelineDirectoryMessages.push_back(swTraceStringsVector);
703     }
704
705     // Calculate the timeline directory binary packet size (in bytes)
706     unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
707                                                messagesDataLength; // 5 messages length
708
709     // Check whether the timeline directory binary packet fits in the given buffer
710     if (timelineDirectoryPacketSize > bufferSize)
711     {
712         return TimelinePacketStatus::BufferExhaustion;
713     }
714
715     // Create packet header
716     uint32_t dataLength = boost::numeric_cast<uint32_t>(messagesDataLength);
717     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, dataLength);
718
719     // Initialize the offset for writing in the buffer
720     unsigned int offset = 0;
721
722     // Write the timeline binary packet header to the buffer
723     WriteUint32(buffer, offset, packetHeader.first);
724     offset += uint32_t_size;
725     WriteUint32(buffer, offset, packetHeader.second);
726     offset += uint32_t_size;
727
728     for (unsigned int i = 0u; i < swTraceTimelineDirectoryMessages.size(); ++i)
729     {
730         // Write the timeline binary packet payload to the buffer
731         WriteUint32(buffer, offset, i); // decl_id
732         offset += uint32_t_size;
733
734         for (std::vector<uint32_t> swTraceString : swTraceTimelineDirectoryMessages[i])
735         {
736             for (uint32_t swTraceDeclStringWord : swTraceString)
737             {
738                 WriteUint32(buffer, offset, swTraceDeclStringWord);
739                 offset += uint32_t_size;
740             }
741         }
742     }
743
744     // Update the number of bytes written
745     numberOfBytesWritten = timelineDirectoryPacketSize;
746
747     return TimelinePacketStatus::Ok;
748 }
749
750 TimelinePacketStatus WriteTimelineEventClassBinaryPacket(uint64_t profilingGuid,
751                                                          unsigned char* buffer,
752                                                          unsigned int bufferSize,
753                                                          unsigned int& numberOfBytesWritten)
754 {
755     // Initialize the output value
756     numberOfBytesWritten = 0;
757
758     // Check that the given buffer is valid
759     if (buffer == nullptr || bufferSize == 0)
760     {
761         return TimelinePacketStatus::BufferExhaustion;
762     }
763
764     // Utils
765     unsigned int uint32_t_size = sizeof(uint32_t);
766     unsigned int uint64_t_size = sizeof(uint64_t);
767
768     // decl_id of the timeline message
769     uint32_t declId = 2;
770
771     // Calculate the length of the data (in bytes)
772     unsigned int packetBodySize = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
773
774     // Calculate the timeline binary packet size (in bytes)
775     unsigned int packetSize = 2 * uint32_t_size + // Header (2 words)
776                               packetBodySize;     // Body
777
778     // Check whether the timeline binary packet fits in the given buffer
779     if (packetSize > bufferSize)
780     {
781         return TimelinePacketStatus::BufferExhaustion;
782     }
783
784     // Create packet header
785     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(packetBodySize);
786
787     // Initialize the offset for writing in the buffer
788     unsigned int offset = 0;
789
790     // Write the timeline binary packet header to the buffer
791     WriteUint32(buffer, offset, packetHeader.first);
792     offset += uint32_t_size;
793     WriteUint32(buffer, offset, packetHeader.second);
794     offset += uint32_t_size;
795
796     // Write the timeline binary packet payload to the buffer
797     WriteUint32(buffer, offset, declId);        // decl_id
798     offset += uint32_t_size;
799     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
800
801     // Update the number of bytes written
802     numberOfBytesWritten = packetSize;
803
804     return TimelinePacketStatus::Ok;
805 }
806
807 TimelinePacketStatus WriteTimelineEventBinaryPacket(uint64_t timestamp,
808                                                     std::thread::id threadId,
809                                                     uint64_t profilingGuid,
810                                                     unsigned char* buffer,
811                                                     unsigned int bufferSize,
812                                                     unsigned int& numberOfBytesWritten)
813 {
814     // Initialize the output value
815     numberOfBytesWritten = 0;
816
817     // Check that the given buffer is valid
818     if (buffer == nullptr || bufferSize == 0)
819     {
820         return TimelinePacketStatus::BufferExhaustion;
821     }
822
823     // Utils
824     unsigned int uint32_t_size = sizeof(uint32_t);
825     unsigned int uint64_t_size = sizeof(uint64_t);
826     unsigned int threadId_size = sizeof(std::thread::id);
827
828     // decl_id of the timeline message
829     uint32_t declId = 4;
830
831     // Calculate the length of the data (in bytes)
832     unsigned int timelineEventPacketDataLength = uint32_t_size + // decl_id
833                                                  uint64_t_size + // Timestamp
834                                                  threadId_size + // Thread id
835                                                  uint64_t_size;  // Profiling GUID
836
837     // Calculate the timeline binary packet size (in bytes)
838     unsigned int timelineEventPacketSize = 2 * uint32_t_size +            // Header (2 words)
839                                            timelineEventPacketDataLength; // Timestamp + thread id + profiling GUID
840
841     // Check whether the timeline binary packet fits in the given buffer
842     if (timelineEventPacketSize > bufferSize)
843     {
844         return TimelinePacketStatus::BufferExhaustion;
845     }
846
847     // Create packet header
848     std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEventPacketDataLength);
849
850     // Initialize the offset for writing in the buffer
851     unsigned int offset = 0;
852
853     // Write the timeline binary packet header to the buffer
854     WriteUint32(buffer, offset, packetHeader.first);
855     offset += uint32_t_size;
856     WriteUint32(buffer, offset, packetHeader.second);
857     offset += uint32_t_size;
858
859     // Write the timeline binary packet payload to the buffer
860     WriteUint32(buffer, offset, declId); // decl_id
861     offset += uint32_t_size;
862     WriteUint64(buffer, offset, timestamp); // Timestamp
863     offset += uint64_t_size;
864     WriteBytes(buffer, offset, &threadId, threadId_size); // Thread id
865     offset += threadId_size;
866     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
867     offset += uint64_t_size;
868
869     // Update the number of bytes written
870     numberOfBytesWritten = timelineEventPacketSize;
871
872     return TimelinePacketStatus::Ok;
873 }
874
875 } // namespace profiling
876
877 } // namespace armnn
878
879 namespace std
880 {
881
882 bool operator==(const std::vector<uint8_t>& left, std::thread::id right)
883 {
884     return std::memcmp(left.data(), &right, left.size()) == 0;
885 }
886
887 } // namespace std