IVGCVSW-3926 Create the Timeline Message Directory Package
[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 std::unique_ptr<IPacketBuffer>& 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 std::unique_ptr<IPacketBuffer>& 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 std::unique_ptr<IPacketBuffer>& 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 std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset)
144 {
145     BOOST_ASSERT(packetBuffer);
146
147     return ReadUint64(packetBuffer->GetReadableData(), offset);
148 }
149
150 uint32_t ReadUint32(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset)
151 {
152     BOOST_ASSERT(packetBuffer);
153
154     return ReadUint32(packetBuffer->GetReadableData(), offset);
155 }
156
157 uint16_t ReadUint16(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset)
158 {
159     BOOST_ASSERT(packetBuffer);
160
161     return ReadUint16(packetBuffer->GetReadableData(), offset);
162 }
163
164 uint8_t ReadUint8(const std::unique_ptr<IPacketBuffer>& 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 TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid,
243                                                     const std::string& label,
244                                                     unsigned char* buffer,
245                                                     unsigned int bufferSize,
246                                                     unsigned int& numberOfBytesWritten)
247 {
248     // Initialize the ouput value
249     numberOfBytesWritten = 0;
250
251     // Check that the given buffer is valid
252     if (buffer == nullptr || bufferSize == 0)
253     {
254         return TimelinePacketStatus::BufferExhaustion;
255     }
256
257     // Utils
258     unsigned int uint32_t_size = sizeof(uint32_t);
259     unsigned int uint64_t_size = sizeof(uint64_t);
260
261     // Convert the label into a SWTrace string
262     std::vector<uint32_t> swTraceLabel;
263     bool result = StringToSwTraceString<SwTraceCharPolicy>(label, swTraceLabel);
264     if (!result)
265     {
266         return TimelinePacketStatus::Error;
267     }
268
269     // Calculate the size of the SWTrace string label (in bytes)
270     unsigned int swTraceLabelSize = boost::numeric_cast<unsigned int>(swTraceLabel.size()) * uint32_t_size;
271
272     // Calculate the length of the data (in bytes)
273     unsigned int timelineLabelPacketDataLength = uint64_t_size +   // Profiling GUID
274                                                  swTraceLabelSize; // Label
275
276     // Calculate the timeline binary packet size (in bytes)
277     unsigned int timelineLabelPacketSize = 2 * uint32_t_size +            // Header (2 words)
278                                            timelineLabelPacketDataLength; // Profiling GUID + label
279
280     // Check whether the timeline binary packet fits in the given buffer
281     if (timelineLabelPacketSize > bufferSize)
282     {
283         return TimelinePacketStatus::BufferExhaustion;
284     }
285
286     // Packet header word 0:
287     // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
288     // 19:25 [7] packet_class: packet class
289     // 16:18 [3] packet_type: packet type
290     // 8:15  [8] reserved: all zeros
291     // 0:7   [8] stream_id: stream identifier
292     uint32_t packetFamily = 1;
293     uint32_t packetClass  = 0;
294     uint32_t packetType   = 1;
295     uint32_t streamId     = 0;
296     uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
297                                  ((packetClass  & 0x0000007F) << 19) |
298                                  ((packetType   & 0x00000007) << 16) |
299                                  ((streamId     & 0x00000007) <<  0);
300
301     // Packet header word 1:
302     // 25:31 [7]  reserved: all zeros
303     // 24    [1]  sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
304     // 0:23  [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
305     uint32_t sequenceNumbered = 0;
306     uint32_t dataLength       = boost::numeric_cast<uint32_t>(timelineLabelPacketDataLength); // Profiling GUID + label
307     uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
308                                  ((dataLength       & 0x00FFFFFF) <<  0);
309
310     // Initialize the offset for writing in the buffer
311     unsigned int offset = 0;
312
313     // Write the timeline binary packet header to the buffer
314     WriteUint32(buffer, offset, packetHeaderWord0);
315     offset += uint32_t_size;
316     WriteUint32(buffer, offset, packetHeaderWord1);
317     offset += uint32_t_size;
318
319     // Write the timeline binary packet payload to the buffer
320     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
321     offset += uint64_t_size;
322     for (uint32_t swTraceLabelWord : swTraceLabel)
323     {
324         WriteUint32(buffer, offset, swTraceLabelWord); // Label
325         offset += uint32_t_size;
326     }
327
328     // Update the number of bytes written
329     numberOfBytesWritten = timelineLabelPacketSize;
330
331     return TimelinePacketStatus::Ok;
332 }
333
334 TimelinePacketStatus WriteTimelineEntityBinaryPacket(uint64_t profilingGuid,
335                                                      unsigned char* buffer,
336                                                      unsigned int bufferSize,
337                                                      unsigned int& numberOfBytesWritten)
338 {
339     // Initialize the ouput value
340     numberOfBytesWritten = 0;
341
342     // Check that the given buffer is valid
343     if (buffer == nullptr || bufferSize == 0)
344     {
345         return TimelinePacketStatus::BufferExhaustion;
346     }
347
348     // Utils
349     unsigned int uint32_t_size = sizeof(uint32_t);
350     unsigned int uint64_t_size = sizeof(uint64_t);
351
352     // Calculate the length of the data (in bytes)
353     unsigned int timelineEntityPacketDataLength = uint64_t_size;   // Profiling GUID
354
355
356     // Calculate the timeline binary packet size (in bytes)
357     unsigned int timelineEntityPacketSize = 2 * uint32_t_size +             // Header (2 words)
358                                            timelineEntityPacketDataLength; // Profiling GUID
359
360     // Check whether the timeline binary packet fits in the given buffer
361     if (timelineEntityPacketSize > bufferSize)
362     {
363         return TimelinePacketStatus::BufferExhaustion;
364     }
365
366     // Packet header word 0:
367     // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
368     // 19:25 [7] packet_class: packet class
369     // 16:18 [3] packet_type: packet type
370     // 8:15  [8] reserved: all zeros
371     // 0:7   [8] stream_id: stream identifier
372     uint32_t packetFamily = 1;
373     uint32_t packetClass  = 0;
374     uint32_t packetType   = 1;
375     uint32_t streamId     = 0;
376     uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
377                                  ((packetClass  & 0x0000007F) << 19) |
378                                  ((packetType   & 0x00000007) << 16) |
379                                  ((streamId     & 0x00000007) <<  0);
380
381     // Packet header word 1:
382     // 25:31 [7]  reserved: all zeros
383     // 24    [1]  sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
384     // 0:23  [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
385     uint32_t sequenceNumbered = 0;
386     uint32_t dataLength       = boost::numeric_cast<uint32_t>(timelineEntityPacketDataLength); // Profiling GUID
387     uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
388                                  ((dataLength       & 0x00FFFFFF) <<  0);
389
390     // Initialize the offset for writing in the buffer
391     unsigned int offset = 0;
392
393     // Write the timeline binary packet header to the buffer
394     WriteUint32(buffer, offset, packetHeaderWord0);
395     offset += uint32_t_size;
396     WriteUint32(buffer, offset, packetHeaderWord1);
397     offset += uint32_t_size;
398
399     // Write the timeline binary packet payload to the buffer
400     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
401
402     // Update the number of bytes written
403     numberOfBytesWritten = timelineEntityPacketSize;
404
405     return TimelinePacketStatus::Ok;
406 }
407
408 TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char* buffer,
409                                                           unsigned int bufferSize,
410                                                           unsigned int& numberOfBytesWritten)
411 {
412     // Initialize the output value
413     numberOfBytesWritten = 0;
414
415     // Check that the given buffer is valid
416     if (buffer == nullptr || bufferSize == 0)
417     {
418         return TimelinePacketStatus::BufferExhaustion;
419     }
420
421     // Utils
422     unsigned int uint32_t_size = sizeof(uint32_t);
423
424     // Packet header word 0:
425     // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
426     // 19:25 [7] packet_class: packet class
427     // 16:18 [3] packet_type: packet type
428     // 8:15  [8] reserved: all zeros
429     // 0:7   [8] stream_id: stream identifier
430     uint32_t packetFamily = 1;
431     uint32_t packetClass  = 0;
432     uint32_t packetType   = 0;
433     uint32_t streamId     = 0;
434     uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
435                                  ((packetClass  & 0x0000007F) << 19) |
436                                  ((packetType   & 0x00000007) << 16) |
437                                  ((streamId     & 0x00000007) <<  0);
438
439     // the payload/data of the packet consists of swtrace event definitions encoded according
440     // to the swtrace directory specification. The messages being the five defined below:
441     // |  decl_id  |  decl_name          |    ui_name            |  arg_types  |  arg_names                          |
442     // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
443     // |    0      |   declareLabel      |   declare label       |    ps       |  guid,value                         |
444     // |    1      |   declareEntity     |   declare entity      |    p        |  guid                               |
445     // |    2      | declareEventClass   |  declare event class  |    p        |  guid                               |
446     // |    3      | declareRelationship | declare relationship  |    Ippp     |  relationshipType,relationshipGuid,
447     //                                                                            headGuid,tailGuid                  |
448     // |    4      |   declareEvent      |   declare event       |    @tp      |  timestamp,threadId,eventGuid       |
449
450     std::vector<std::vector<std::string>> timelineDirectoryMessages =
451         { {"declareLabel", "declare label", "ps", "guid,value"},
452           {"declareEntity", "declare entity", "p", "guid"},
453           {"declareEventClass", "declare event class", "p", "guid"},
454           {"declareRelationship", "declare relationship",
455               "Ippp", "relationshipType,relationshipGuid,headGuid,tailGuid"},
456           {"declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid"} };
457
458     unsigned int messagesDataLength = 0u;
459     std::vector<std::vector<std::vector<uint32_t>>> swTraceTimelineDirectoryMessages;
460
461     for (const auto& timelineDirectoryMessage : timelineDirectoryMessages)
462     {
463         messagesDataLength += uint32_t_size; // decl_id
464
465         std::vector<std::vector<uint32_t>> swTraceStringsVector;
466         for (const auto& label : timelineDirectoryMessage)
467         {
468             std::vector<uint32_t> swTraceString;
469             bool result = StringToSwTraceString<SwTraceCharPolicy>(label, swTraceString);
470             if (!result)
471             {
472                 return TimelinePacketStatus::Error;
473             }
474
475             messagesDataLength += boost::numeric_cast<unsigned int>(swTraceString.size()) * uint32_t_size;
476             swTraceStringsVector.push_back(swTraceString);
477         }
478         swTraceTimelineDirectoryMessages.push_back(swTraceStringsVector);
479     }
480
481     // Calculate the timeline directory binary packet size (in bytes)
482     unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
483                                                messagesDataLength; // 5 messages length
484
485     // Check whether the timeline directory binary packet fits in the given buffer
486     if (timelineDirectoryPacketSize > bufferSize)
487     {
488         return TimelinePacketStatus::BufferExhaustion;
489     }
490
491     // Packet header word 1:
492     // 25:31 [7]  reserved: all zeros
493     // 24    [1]  sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
494     // 0:23  [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
495     uint32_t sequenceNumbered  = 0;
496     uint32_t dataLength        = boost::numeric_cast<uint32_t>(messagesDataLength);
497     uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
498                                  ((dataLength       & 0x00FFFFFF) <<  0);
499
500     // Initialize the offset for writing in the buffer
501     unsigned int offset = 0;
502
503     // Write the timeline binary packet header to the buffer
504     WriteUint32(buffer, offset, packetHeaderWord0);
505     offset += uint32_t_size;
506     WriteUint32(buffer, offset, packetHeaderWord1);
507     offset += uint32_t_size;
508
509     for (unsigned int i = 0u; i < swTraceTimelineDirectoryMessages.size(); ++i)
510     {
511         // Write the timeline binary packet payload to the buffer
512         WriteUint32(buffer, offset, i); // decl_id
513         offset += uint32_t_size;
514
515         for (std::vector<uint32_t> swTraceString : swTraceTimelineDirectoryMessages[i])
516         {
517             for (uint32_t swTraceDeclStringWord : swTraceString)
518             {
519                 WriteUint32(buffer, offset, swTraceDeclStringWord);
520                 offset += uint32_t_size;
521             }
522         }
523     }
524
525     // Update the number of bytes written
526     numberOfBytesWritten = timelineDirectoryPacketSize;
527
528     return TimelinePacketStatus::Ok;
529 }
530
531 } // namespace profiling
532
533 } // namespace armnn