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