IVGCVSW-5166 Pull out the common and server side code into standalone libraries
[platform/upstream/armnn.git] / src / profiling / SendCounterPacket.cpp
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "SendCounterPacket.hpp"
7 #include <common/include/EncodeVersion.hpp>
8
9 #include <armnn/Exceptions.hpp>
10 #include <armnn/Conversion.hpp>
11 #include <Processes.hpp>
12 #include <armnn/utility/Assert.hpp>
13 #include <common/include/Constants.hpp>
14 #include <common/include/SwTrace.hpp>
15
16 #include <boost/format.hpp>
17 #include <boost/numeric/conversion/cast.hpp>
18
19 #include <cstring>
20
21 namespace armnn
22 {
23
24 namespace profiling
25 {
26
27 using boost::numeric_cast;
28
29 void SendCounterPacket::SendStreamMetaDataPacket()
30 {
31     const std::string info(GetSoftwareInfo());
32     const std::string hardwareVersion(GetHardwareVersion());
33     const std::string softwareVersion(GetSoftwareVersion());
34     const std::string processName = GetProcessName().substr(0, 60);
35
36     const uint32_t infoSize =            numeric_cast<uint32_t>(info.size()) + 1;
37     const uint32_t hardwareVersionSize = numeric_cast<uint32_t>(hardwareVersion.size()) + 1;
38     const uint32_t softwareVersionSize = numeric_cast<uint32_t>(softwareVersion.size()) + 1;
39     const uint32_t processNameSize =     numeric_cast<uint32_t>(processName.size()) + 1;
40
41     const uint32_t sizeUint32 = sizeof(uint32_t);
42
43     const uint32_t headerSize = 2 * sizeUint32;
44     const uint32_t bodySize = 10 * sizeUint32;
45     const uint32_t packetVersionCountSize = sizeUint32;
46
47     // Supported Packets
48     // Packet Encoding version 1.0.0
49     // Control packet family
50     //   Stream metadata packet (packet family=0; packet id=0)
51     //   Connection Acknowledged packet ( packet family=0, packet id=1) Version 1.0.0
52     //   Counter Directory packet (packet family=0; packet id=2) Version 1.0.0
53     //   Request Counter Directory packet ( packet family=0, packet id=3) Version 1.0.0
54     //   Periodic Counter Selection packet ( packet family=0, packet id=4) Version 1.0.0
55     //   Per Job Counter Selection packet ( packet family=0, packet id=5) Version 1.0.0
56     //   Activate Timeline Reporting (packet family = 0, packet id = 6) Version 1.0.0
57     //   Deactivate Timeline Reporting (packet family = 0, packet id = 7) Version 1.0.0
58     // Counter Packet Family
59     //   Periodic Counter Capture (packet_family = 3, packet_class = 0, packet_type = 0) Version 1.0.0
60     //   Per-Job Counter Capture (packet_family = 3, packet_class = 1, packet_type = 0,1) Version  1.0.0
61     // Timeline Packet Family
62     //   Timeline Message Directory (packet_family = 1, packet_class = 0, packet_type = 0) Version 1.0.0
63     //   Timeline Message (packet_family = 1, packet_class = 0, packet_type = 1) Version 1.0.0
64     std::vector<std::pair<uint32_t, uint32_t>> packetVersions;
65     packetVersions.push_back(std::make_pair(ConstructHeader(0, 0), arm::pipe::EncodeVersion(1, 0, 0)));
66     packetVersions.push_back(std::make_pair(ConstructHeader(0, 1), arm::pipe::EncodeVersion(1, 0, 0)));
67     packetVersions.push_back(std::make_pair(ConstructHeader(0, 2), arm::pipe::EncodeVersion(1, 0, 0)));
68     packetVersions.push_back(std::make_pair(ConstructHeader(0, 3), arm::pipe::EncodeVersion(1, 0, 0)));
69     packetVersions.push_back(std::make_pair(ConstructHeader(0, 4), arm::pipe::EncodeVersion(1, 0, 0)));
70     packetVersions.push_back(std::make_pair(ConstructHeader(0, 5), arm::pipe::EncodeVersion(1, 0, 0)));
71     packetVersions.push_back(std::make_pair(ConstructHeader(0, 6), arm::pipe::EncodeVersion(1, 0, 0)));
72     packetVersions.push_back(std::make_pair(ConstructHeader(0, 7), arm::pipe::EncodeVersion(1, 0, 0)));
73     packetVersions.push_back(std::make_pair(ConstructHeader(3, 0, 0), arm::pipe::EncodeVersion(1, 0, 0)));
74     packetVersions.push_back(std::make_pair(ConstructHeader(3, 1, 0), arm::pipe::EncodeVersion(1, 0, 0)));
75     packetVersions.push_back(std::make_pair(ConstructHeader(3, 1, 1), arm::pipe::EncodeVersion(1, 0, 0)));
76     packetVersions.push_back(std::make_pair(ConstructHeader(1, 0, 0), arm::pipe::EncodeVersion(1, 0, 0)));
77     packetVersions.push_back(std::make_pair(ConstructHeader(1, 0, 1), arm::pipe::EncodeVersion(1, 0, 0)));
78     uint32_t numberOfVersions = numeric_cast<uint32_t>(packetVersions.size());
79     uint32_t packetVersionSize = numeric_cast<uint32_t>(numberOfVersions * 2 * sizeUint32);
80
81     const uint32_t payloadSize = numeric_cast<uint32_t>(infoSize + hardwareVersionSize + softwareVersionSize +
82                                                   processNameSize + packetVersionCountSize + packetVersionSize);
83
84     const uint32_t totalSize = headerSize + bodySize + payloadSize;
85     uint32_t offset = 0;
86     uint32_t reserved = 0;
87
88     IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
89
90     if (writeBuffer == nullptr || reserved < totalSize)
91     {
92         CancelOperationAndThrow<BufferExhaustion>(
93             writeBuffer,
94             boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
95     }
96
97     try
98     {
99         // Create header
100
101         WriteUint32(writeBuffer, offset, 0);
102         offset += sizeUint32;
103         WriteUint32(writeBuffer, offset, totalSize - headerSize);
104
105         // Packet body
106
107         offset += sizeUint32;
108         WriteUint32(writeBuffer, offset, arm::pipe::PIPE_MAGIC); // pipe_magic
109         offset += sizeUint32;
110         WriteUint32(writeBuffer, offset, arm::pipe::EncodeVersion(1, 0, 0)); // stream_metadata_version
111         offset += sizeUint32;
112         WriteUint32(writeBuffer, offset, MAX_METADATA_PACKET_LENGTH); // max_data_length
113         offset += sizeUint32;
114         int pid = armnnUtils::Processes::GetCurrentId();
115         WriteUint32(writeBuffer, offset, numeric_cast<uint32_t>(pid)); // pid
116         offset += sizeUint32;
117         uint32_t poolOffset = bodySize;
118         WriteUint32(writeBuffer, offset, poolOffset); // offset_info
119         offset += sizeUint32;
120         poolOffset += infoSize;
121         WriteUint32(writeBuffer, offset, poolOffset); // offset_hw_version
122         offset += sizeUint32;
123         poolOffset += hardwareVersionSize;
124         WriteUint32(writeBuffer, offset, poolOffset); // offset_sw_version
125         offset += sizeUint32;
126         poolOffset += softwareVersionSize;
127         WriteUint32(writeBuffer, offset, poolOffset); // offset_process_name
128         offset += sizeUint32;
129         poolOffset += processNameSize;
130         WriteUint32(writeBuffer, offset, poolOffset); // offset_packet_version_table
131         offset += sizeUint32;
132         WriteUint32(writeBuffer, offset, 0); // reserved
133         offset += sizeUint32;
134
135         // Pool
136
137         if (infoSize)
138         {
139             memcpy(&writeBuffer->GetWritableData()[offset], info.c_str(), infoSize);
140             offset += infoSize;
141         }
142
143         memcpy(&writeBuffer->GetWritableData()[offset], hardwareVersion.c_str(), hardwareVersionSize);
144         offset += hardwareVersionSize;
145         memcpy(&writeBuffer->GetWritableData()[offset], softwareVersion.c_str(), softwareVersionSize);
146         offset += softwareVersionSize;
147         memcpy(&writeBuffer->GetWritableData()[offset], processName.c_str(), processNameSize);
148         offset += processNameSize;
149
150         if (!packetVersions.empty())
151         {
152             // Packet Version Count
153             WriteUint32(writeBuffer, offset, numberOfVersions << 16);
154             offset += sizeUint32;
155
156             // Packet Version Entries
157             for (std::pair<uint32_t, uint32_t>& packetVersion : packetVersions)
158             {
159                 WriteUint32(writeBuffer, offset, packetVersion.first);
160                 offset += sizeUint32;
161                 WriteUint32(writeBuffer, offset, packetVersion.second);
162                 offset += sizeUint32;
163             }
164         }
165     }
166     catch(...)
167     {
168         CancelOperationAndThrow<RuntimeException>(writeBuffer, "Error processing packet.");
169     }
170
171     m_BufferManager.Commit(writeBuffer, totalSize, false);
172 }
173
174 bool SendCounterPacket::CreateCategoryRecord(const CategoryPtr& category,
175                                              const Counters& counters,
176                                              CategoryRecord& categoryRecord,
177                                              std::string& errorMessage)
178 {
179     using namespace boost::numeric;
180
181     ARMNN_ASSERT(category);
182
183     const std::string& categoryName = category->m_Name;
184     ARMNN_ASSERT(!categoryName.empty());
185
186     // Remove any duplicate counters
187     std::vector<uint16_t> categoryCounters;
188     for (size_t counterIndex = 0; counterIndex < category->m_Counters.size(); ++counterIndex)
189     {
190         uint16_t counterUid = category->m_Counters.at(counterIndex);
191         auto it = counters.find(counterUid);
192         if (it == counters.end())
193         {
194             errorMessage = boost::str(boost::format("Counter (%1%) not found in category (%2%)")
195                                       % counterUid % category->m_Name );
196             return false;
197         }
198
199         const CounterPtr& counter = it->second;
200
201         if (counterUid == counter->m_MaxCounterUid)
202         {
203             categoryCounters.emplace_back(counterUid);
204         }
205     }
206     if (categoryCounters.empty())
207     {
208         errorMessage = boost::str(boost::format("No valid counters found in category (%1%)")% categoryName);
209         return false;
210     }
211
212     // Utils
213     const size_t uint32_t_size = sizeof(uint32_t);
214
215     // Convert the device name into a SWTrace namestring
216     std::vector<uint32_t> categoryNameBuffer;
217     if (!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>(categoryName, categoryNameBuffer))
218     {
219         errorMessage = boost::str(boost::format("Cannot convert the name of category (%1%) to an SWTrace namestring")
220                                   % categoryName);
221         return false;
222     }
223
224     // Category record word 1:
225     // 16:31 [16] event_count: number of events belonging to this category
226     // 0:15  [16] reserved: all zeros
227     const uint32_t categoryRecordWord1 = static_cast<uint32_t>(categoryCounters.size()) << 16;
228
229     // Category record word 2:
230     // 0:31 [32] event_pointer_table_offset: offset from the beginning of the category data pool to
231     //                                       the event_pointer_table
232     const uint32_t categoryRecordWord2 = static_cast<uint32_t>(3u * uint32_t_size);
233
234     // Process the event records
235     const size_t counterCount = categoryCounters.size();
236     std::vector<EventRecord> eventRecords(counterCount);
237     std::vector<uint32_t> eventRecordOffsets(counterCount, 0);
238     size_t eventRecordsSize = 0;
239     uint32_t eventRecordsOffset =
240             numeric_cast<uint32_t>((eventRecords.size() + categoryNameBuffer.size()) * uint32_t_size);
241     for (size_t counterIndex = 0, eventRecordIndex = 0, eventRecordOffsetIndex = 0;
242          counterIndex < counterCount;
243          counterIndex++, eventRecordIndex++, eventRecordOffsetIndex++)
244     {
245         uint16_t counterUid = categoryCounters.at(counterIndex);
246         auto it = counters.find(counterUid);
247         const CounterPtr& counter = it->second;
248
249         EventRecord& eventRecord = eventRecords.at(eventRecordIndex);
250         if (!CreateEventRecord(counter, eventRecord, errorMessage))
251         {
252             return false;
253         }
254
255         // Update the total size in words of the event records
256         eventRecordsSize += eventRecord.size();
257
258         // Add the event record offset to the event pointer table offset field
259         eventRecordOffsets[eventRecordOffsetIndex] = eventRecordsOffset;
260         eventRecordsOffset += numeric_cast<uint32_t>(eventRecord.size() * uint32_t_size);
261     }
262
263     // Category record word 3:
264     // 0:31 [32] name_offset (offset from the beginning of the category data pool to the name field)
265     const uint32_t categoryRecordWord3 = numeric_cast<uint32_t>((3u + eventRecordOffsets.size()) * uint32_t_size);
266
267     // Calculate the size in words of the category record
268     const size_t categoryRecordSize = 3u +// The size of the fixed part (device + counter_set + event_count +
269                                           // reserved + event_pointer_table_offset + name_offset)
270                                       eventRecordOffsets.size() + // The size of the variable part (
271                                       categoryNameBuffer.size() + // the event pointer table + the category name
272                                       eventRecordsSize;           // including the null-terminator + the event records)
273
274     // Allocate the necessary space for the category record
275     categoryRecord.resize(categoryRecordSize);
276
277     ARMNN_NO_CONVERSION_WARN_BEGIN
278     // Create the category record
279     categoryRecord[0] = categoryRecordWord1; // event_count + reserved
280     categoryRecord[1] = categoryRecordWord2; // event_pointer_table_offset
281     categoryRecord[2] = categoryRecordWord3; // name_offset
282     auto offset = categoryRecord.begin() + 3u;
283     std::copy(eventRecordOffsets.begin(), eventRecordOffsets.end(), offset); // event_pointer_table
284     offset += eventRecordOffsets.size();
285     std::copy(categoryNameBuffer.begin(), categoryNameBuffer.end(), offset); // name
286     offset += categoryNameBuffer.size();
287     for (const EventRecord& eventRecord : eventRecords)
288     {
289         std::copy(eventRecord.begin(), eventRecord.end(), offset); // event_record
290         offset += eventRecord.size();
291     }
292     ARMNN_NO_CONVERSION_WARN_END
293
294     return true;
295 }
296
297 bool SendCounterPacket::CreateDeviceRecord(const DevicePtr& device,
298                                            DeviceRecord& deviceRecord,
299                                            std::string& errorMessage)
300 {
301     ARMNN_ASSERT(device);
302
303     uint16_t deviceUid = device->m_Uid;
304     const std::string& deviceName = device->m_Name;
305     uint16_t deviceCores = device->m_Cores;
306
307     ARMNN_ASSERT(!deviceName.empty());
308
309     // Device record word 0:
310     // 16:31 [16] uid: the unique identifier for the device
311     // 0:15  [16] cores: the number of individual streams of counters for one or more cores of some device
312     const uint32_t deviceRecordWord0 = (static_cast<uint32_t>(deviceUid) << 16) |
313                                  (static_cast<uint32_t>(deviceCores));
314
315     // Device record word 1:
316     // 0:31 [32] name_offset: offset from the beginning of the device record pool to the name field
317     const uint32_t deviceRecordWord1 = 8u; // The offset is always eight here, as the name field is always
318                                            // the first (and only) item in the pool and there are two device words
319
320     // Convert the device name into a SWTrace string
321     std::vector<uint32_t> deviceNameBuffer;
322     if (!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>(deviceName, deviceNameBuffer))
323     {
324         errorMessage = boost::str(boost::format("Cannot convert the name of device %1% (%2%) to an SWTrace string")
325                                   % deviceUid
326                                   % deviceName);
327         return false;
328     }
329
330     // Calculate the size in words of the device record
331     const size_t deviceRecordSize = 2u + // The size of the fixed part (uid + cores + name_offset)
332                               deviceNameBuffer.size(); // The size of the variable part (the device name including
333                                                        // the null-terminator)
334
335     // Allocate the necessary space for the device record
336     deviceRecord.resize(deviceRecordSize);
337
338     // Create the device record
339     deviceRecord[0] = deviceRecordWord0; // uid + core
340     deviceRecord[1] = deviceRecordWord1; // name_offset
341     auto offset = deviceRecord.begin() + 2u;
342     std::copy(deviceNameBuffer.begin(), deviceNameBuffer.end(), offset); // name
343
344     return true;
345 }
346
347 bool SendCounterPacket::CreateCounterSetRecord(const CounterSetPtr& counterSet,
348                                                CounterSetRecord& counterSetRecord,
349                                                std::string& errorMessage)
350 {
351     ARMNN_ASSERT(counterSet);
352
353     uint16_t counterSetUid = counterSet->m_Uid;
354     const std::string& counterSetName = counterSet->m_Name;
355     uint16_t counterSetCount = counterSet->m_Count;
356
357     ARMNN_ASSERT(!counterSetName.empty());
358
359     // Counter set record word 0:
360     // 16:31 [16] uid: the unique identifier for the counter_set
361     // 0:15  [16] count: the number of counters which can be active in this set at any one time
362     const uint32_t counterSetRecordWord0 = (static_cast<uint32_t>(counterSetUid) << 16) |
363                                            (static_cast<uint32_t>(counterSetCount));
364
365     // Counter set record word 1:
366     // 0:31 [32] name_offset: offset from the beginning of the counter set pool to the name field
367     const uint32_t counterSetRecordWord1 = 8u; // The offset is always eight here, as the name field is always
368                                                // the first (and only) item in the pool after the two counter set words
369
370     // Convert the device name into a SWTrace namestring
371     std::vector<uint32_t> counterSetNameBuffer;
372     if (!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>(counterSet->m_Name, counterSetNameBuffer))
373     {
374         errorMessage = boost::str(boost::format("Cannot convert the name of counter set %1% (%2%) to "
375                                                 "an SWTrace namestring")
376                                   % counterSetUid
377                                   % counterSetName);
378         return false;
379     }
380
381     // Calculate the size in words of the counter set record
382     const size_t counterSetRecordSize = 2u + // The size of the fixed part (uid + cores + name_offset)
383                                         counterSetNameBuffer.size(); // The size of the variable part (the counter set
384                                                                      // name including the null-terminator)
385
386     // Allocate the space for the counter set record
387     counterSetRecord.resize(counterSetRecordSize);
388
389     // Create the counter set record
390     counterSetRecord[0] = counterSetRecordWord0; // uid + core
391     counterSetRecord[1] = counterSetRecordWord1; // name_offset
392     auto offset = counterSetRecord.begin() + 2u;
393     std::copy(counterSetNameBuffer.begin(), counterSetNameBuffer.end(), offset); // name
394
395     return true;
396 }
397
398 bool SendCounterPacket::CreateEventRecord(const CounterPtr& counter,
399                                           EventRecord& eventRecord,
400                                           std::string& errorMessage)
401 {
402     using namespace boost::numeric;
403
404     ARMNN_ASSERT(counter);
405
406     uint16_t           counterUid           = counter->m_Uid;
407     uint16_t           maxCounterUid        = counter->m_MaxCounterUid;
408     uint16_t           deviceUid            = counter->m_DeviceUid;
409     uint16_t           counterSetUid        = counter->m_CounterSetUid;
410     uint16_t           counterClass         = counter->m_Class;
411     uint16_t           counterInterpolation = counter->m_Interpolation;
412     double             counterMultiplier    = counter->m_Multiplier;
413     const std::string& counterName          = counter->m_Name;
414     const std::string& counterDescription   = counter->m_Description;
415     const std::string& counterUnits         = counter->m_Units;
416
417     ARMNN_ASSERT(counterClass == 0 || counterClass == 1);
418     ARMNN_ASSERT(counterInterpolation == 0 || counterInterpolation == 1);
419     ARMNN_ASSERT(counterMultiplier);
420
421     // Utils
422     const size_t uint32_t_size = sizeof(uint32_t);
423     // eventRecordBlockSize is the size of the fixed part
424     // (counter_uid + max_counter_uid + device +
425     // counter_set + class + interpolation +
426     // multiplier + name_offset + description_offset +
427     // units_offset)
428     const size_t eventRecordBlockSize = 8u;
429
430     // Event record word 0:
431     // 16:31 [16] max_counter_uid: if the device this event is associated with has more than one core and there
432     //                             is one of these counters per core this value will be set to
433     //                             (counter_uid + cores (from device_record)) - 1.
434     //                             If there is only a single core then this value will be the same as
435     //                             the counter_uid value
436     // 0:15  [16] count_uid: unique ID for the counter. Must be unique across all counters in all categories
437     const uint32_t eventRecordWord0 = (static_cast<uint32_t>(maxCounterUid) << 16) |
438                                       (static_cast<uint32_t>(counterUid));
439
440     // Event record word 1:
441     // 16:31 [16] device: UID of the device this event is associated with. Set to zero if the event is NOT
442     //                    associated with a device
443     // 0:15  [16] counter_set: UID of the counter_set this event is associated with. Set to zero if the event
444     //                         is NOT associated with a counter_set
445     const uint32_t eventRecordWord1 = (static_cast<uint32_t>(deviceUid) << 16) |
446                                       (static_cast<uint32_t>(counterSetUid));
447
448     // Event record word 2:
449     // 16:31 [16] class: type describing how to treat each data point in a stream of data points
450     // 0:15  [16] interpolation: type describing how to interpolate each data point in a stream of data points
451     const uint32_t eventRecordWord2 = (static_cast<uint32_t>(counterClass) << 16) |
452                                       (static_cast<uint32_t>(counterInterpolation));
453
454     // Event record word 3-4:
455     // 0:63 [64] multiplier: internal data stream is represented as integer values, this allows scaling of
456     //                       those values as if they are fixed point numbers. Zero is not a valid value
457     uint32_t multiplier[2] = { 0u, 0u };
458     ARMNN_ASSERT(sizeof(counterMultiplier) == sizeof(multiplier));
459     std::memcpy(multiplier, &counterMultiplier, sizeof(multiplier));
460     const uint32_t eventRecordWord3 = multiplier[0];
461     const uint32_t eventRecordWord4 = multiplier[1];
462
463     // Event record word 5:
464     // 0:31 [32] name_offset: offset from the beginning of the event record pool to the name field
465     const uint32_t eventRecordWord5 = static_cast<uint32_t>(eventRecordBlockSize * uint32_t_size);
466
467     // Convert the counter name into a SWTrace string
468     std::vector<uint32_t> counterNameBuffer;
469     if (!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>(counterName, counterNameBuffer))
470     {
471         errorMessage = boost::str(boost::format("Cannot convert the name of counter %1% (name: %2%) "
472                                                 "to an SWTrace string")
473                                   % counterUid
474                                   % counterName);
475         return false;
476     }
477
478     // Event record word 6:
479     // 0:31 [32] description_offset: offset from the beginning of the event record pool to the description field
480     // The size of the name buffer in bytes
481     uint32_t eventRecordWord6 =
482             static_cast<uint32_t>((counterNameBuffer.size() + eventRecordBlockSize) * uint32_t_size);
483
484     // Convert the counter description into a SWTrace string
485     std::vector<uint32_t> counterDescriptionBuffer;
486     if (!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>(counterDescription, counterDescriptionBuffer))
487     {
488         errorMessage = boost::str(boost::format("Cannot convert the description of counter %1% (description: %2%) "
489                                                 "to an SWTrace string")
490                                   % counterUid
491                                   % counterName);
492         return false;
493     }
494
495     // Event record word 7:
496     // 0:31 [32] units_offset: (optional) offset from the beginning of the event record pool to the units field.
497     //                         An offset value of zero indicates this field is not provided
498     bool includeUnits = !counterUnits.empty();
499     // The size of the description buffer in bytes
500     const uint32_t eventRecordWord7 = includeUnits ?
501                                 eventRecordWord6 +
502                                 numeric_cast<uint32_t>(counterDescriptionBuffer.size()
503                                 * uint32_t_size) :
504                                 0;
505
506     // Convert the counter units into a SWTrace namestring (optional)
507     std::vector<uint32_t> counterUnitsBuffer;
508     if (includeUnits)
509     {
510         // Convert the counter units into a SWTrace namestring
511         if (!arm::pipe::StringToSwTraceString<arm::pipe::SwTraceNameCharPolicy>(counterUnits, counterUnitsBuffer))
512         {
513             errorMessage = boost::str(boost::format("Cannot convert the units of counter %1% (units: %2%) "
514                                                     "to an SWTrace string")
515                                       % counterUid
516                                       % counterName);
517             return false;
518         }
519     }
520
521     // Calculate the size in words of the event record
522     const size_t eventRecordSize = eventRecordBlockSize +
523                                    counterNameBuffer.size() +        // The size of the variable part (the counter name,
524                                    counterDescriptionBuffer.size() + // description and units
525                                    counterUnitsBuffer.size();        // including the null-terminator)
526
527     // Allocate the space for the event record
528     eventRecord.resize(eventRecordSize);
529
530     ARMNN_NO_CONVERSION_WARN_BEGIN
531     // Create the event record
532     eventRecord[0] = eventRecordWord0; // max_counter_uid + counter_uid
533     eventRecord[1] = eventRecordWord1; // device + counter_set
534     eventRecord[2] = eventRecordWord2; // class + interpolation
535     eventRecord[3] = eventRecordWord3; // multiplier
536     eventRecord[4] = eventRecordWord4; // multiplier
537     eventRecord[5] = eventRecordWord5; // name_offset
538     eventRecord[6] = eventRecordWord6; // description_offset
539     eventRecord[7] = eventRecordWord7; // units_offset
540     auto offset = eventRecord.begin() + 8u;
541     std::copy(counterNameBuffer.begin(), counterNameBuffer.end(), offset); // name
542     offset += counterNameBuffer.size();
543     std::copy(counterDescriptionBuffer.begin(), counterDescriptionBuffer.end(), offset); // description
544     if (includeUnits)
545     {
546         offset += counterDescriptionBuffer.size();
547         std::copy(counterUnitsBuffer.begin(), counterUnitsBuffer.end(), offset); // units
548     }
549     ARMNN_NO_CONVERSION_WARN_END
550
551     return true;
552 }
553
554 void SendCounterPacket::SendCounterDirectoryPacket(const ICounterDirectory& counterDirectory)
555 {
556     using namespace boost::numeric;
557
558     // Get the amount of data that needs to be put into the packet
559     const uint16_t categoryCount    = counterDirectory.GetCategoryCount();
560     const uint16_t deviceCount      = counterDirectory.GetDeviceCount();
561     const uint16_t counterSetCount  = counterDirectory.GetCounterSetCount();
562
563     // Utils
564     const size_t uint32_t_size = sizeof(uint32_t);
565     const size_t packetHeaderSize = 2u;
566     const size_t bodyHeaderSize = 6u;
567     const uint32_t bodyHeaderSizeBytes = bodyHeaderSize * uint32_t_size;
568
569     // Initialize the offset for the pointer tables
570     uint32_t pointerTableOffset = 0;
571
572     // --------------
573     // Device records
574     // --------------
575
576     // Process device records
577     std::vector<DeviceRecord> deviceRecords(deviceCount);
578     const Devices& devices = counterDirectory.GetDevices();
579     std::vector<uint32_t> deviceRecordOffsets(deviceCount, 0); // device_records_pointer_table
580     size_t deviceRecordsSize = 0;
581     size_t deviceIndex = 0;
582     size_t deviceRecordOffsetIndex = 0;
583
584     pointerTableOffset = numeric_cast<uint32_t>(deviceCount     * uint32_t_size +
585                                                 counterSetCount * uint32_t_size +
586                                                 categoryCount   * uint32_t_size);
587     for (auto it = devices.begin(); it != devices.end(); it++)
588     {
589         const DevicePtr& device = it->second;
590         DeviceRecord& deviceRecord = deviceRecords.at(deviceIndex);
591
592         std::string errorMessage;
593         if (!CreateDeviceRecord(device, deviceRecord, errorMessage))
594         {
595             CancelOperationAndThrow<RuntimeException>(errorMessage);
596         }
597
598         // Update the total size in words of the device records
599         deviceRecordsSize += deviceRecord.size();
600
601         // Add the device record offset to the device records pointer table offset field
602         deviceRecordOffsets[deviceRecordOffsetIndex] = pointerTableOffset;
603         pointerTableOffset += numeric_cast<uint32_t>(deviceRecord.size() * uint32_t_size);
604
605         deviceIndex++;
606         deviceRecordOffsetIndex++;
607     }
608
609     // -------------------
610     // Counter set records
611     // -------------------
612
613     // Process counter set records
614     std::vector<CounterSetRecord> counterSetRecords(counterSetCount);
615     const CounterSets& counterSets = counterDirectory.GetCounterSets();
616     std::vector<uint32_t> counterSetRecordOffsets(counterSetCount, 0); // counter_set_records_pointer_table
617     size_t counterSetRecordsSize = 0;
618     size_t counterSetIndex = 0;
619     size_t counterSetRecordOffsetIndex = 0;
620
621     pointerTableOffset -= numeric_cast<uint32_t>(deviceCount * uint32_t_size);
622     for (auto it = counterSets.begin(); it != counterSets.end(); it++)
623     {
624         const CounterSetPtr& counterSet = it->second;
625         CounterSetRecord& counterSetRecord = counterSetRecords.at(counterSetIndex);
626
627         std::string errorMessage;
628         if (!CreateCounterSetRecord(counterSet, counterSetRecord, errorMessage))
629         {
630             CancelOperationAndThrow<RuntimeException>(errorMessage);
631         }
632
633         // Update the total size in words of the counter set records
634         counterSetRecordsSize += counterSetRecord.size();
635
636         // Add the counter set record offset to the counter set records pointer table offset field
637         counterSetRecordOffsets[counterSetRecordOffsetIndex] = pointerTableOffset;
638         pointerTableOffset += numeric_cast<uint32_t>(counterSetRecord.size() * uint32_t_size);
639
640         counterSetIndex++;
641         counterSetRecordOffsetIndex++;
642     }
643
644     // ----------------
645     // Category records
646     // ----------------
647
648     // Process category records
649     std::vector<CategoryRecord> categoryRecords(categoryCount);
650     const Categories& categories = counterDirectory.GetCategories();
651     std::vector<uint32_t> categoryRecordOffsets(categoryCount, 0); // category_records_pointer_table
652     size_t categoryRecordsSize = 0;
653     size_t categoryIndex = 0;
654     size_t categoryRecordOffsetIndex = 0;
655
656     pointerTableOffset -= numeric_cast<uint32_t>(counterSetCount * uint32_t_size);
657     for (auto it = categories.begin(); it != categories.end(); it++)
658     {
659         const CategoryPtr& category = *it;
660         CategoryRecord& categoryRecord = categoryRecords.at(categoryIndex);
661
662         std::string errorMessage;
663         if (!CreateCategoryRecord(category, counterDirectory.GetCounters(), categoryRecord, errorMessage))
664         {
665             CancelOperationAndThrow<RuntimeException>(errorMessage);
666         }
667
668         // Update the total size in words of the category records
669         categoryRecordsSize += categoryRecord.size();
670
671         // Add the category record offset to the category records pointer table offset field
672         categoryRecordOffsets[categoryRecordOffsetIndex] = pointerTableOffset;
673         pointerTableOffset += numeric_cast<uint32_t>(categoryRecord.size() * uint32_t_size);
674
675         categoryIndex++;
676         categoryRecordOffsetIndex++;
677     }
678
679     // Calculate the length in words of the counter directory packet's data (excludes the packet header size)
680     const size_t counterDirectoryPacketDataLength =
681                  bodyHeaderSize +                 // The size of the body header
682                  deviceRecordOffsets.size() +     // The size of the device records pointer table
683                  counterSetRecordOffsets.size() + // The size of counter set pointer table
684                  categoryRecordOffsets.size() +   // The size of category records pointer table
685                  deviceRecordsSize +              // The total size of the device records
686                  counterSetRecordsSize +          // The total size of the counter set records
687                  categoryRecordsSize;             // The total size of the category records
688
689     // Calculate the size in words of the counter directory packet (the data length plus the packet header size)
690     const size_t counterDirectoryPacketSize = packetHeaderSize +                // The size of the packet header
691                                               counterDirectoryPacketDataLength; // The data length
692
693     // Allocate the necessary space for the counter directory packet
694     std::vector<uint32_t> counterDirectoryPacket(counterDirectoryPacketSize, 0);
695
696     // -------------
697     // Packet header
698     // -------------
699
700     // Packet header word 0:
701     // 26:31 [6]  packet_family: control Packet Family
702     // 16:25 [10] packet_id: packet identifier
703     // 8:15  [8]  reserved: all zeros
704     // 0:7   [8]  reserved: all zeros
705     uint32_t packetFamily = 0;
706     uint32_t packetId = 2;
707     uint32_t packetHeaderWord0 = ((packetFamily & 0x3F) << 26) | ((packetId & 0x3FF) << 16);
708
709     // Packet header word 1:
710     // 0:31 [32] data_length: length of data, in bytes
711     uint32_t packetHeaderWord1 = numeric_cast<uint32_t>(counterDirectoryPacketDataLength * uint32_t_size);
712
713     // Create the packet header
714     uint32_t packetHeader[2]
715     {
716         packetHeaderWord0, // packet_family + packet_id + reserved + reserved
717         packetHeaderWord1  // data_length
718     };
719
720     // -----------
721     // Body header
722     // -----------
723
724     // Body header word 0:
725     // 16:31 [16] device_records_count: number of entries in the device_records_pointer_table
726     // 0:15  [16] reserved: all zeros
727     const uint32_t bodyHeaderWord0 = static_cast<uint32_t>(deviceCount) << 16;
728
729     // Body header word 1:
730     // 0:31 [32] device_records_pointer_table_offset: offset to the device_records_pointer_table
731     const uint32_t bodyHeaderWord1 = bodyHeaderSizeBytes; // The offset is always the bodyHeaderSize,
732                                                           // as the device record pointer table field
733                                                           // is always the first item in the pool
734
735     // Body header word 2:
736     // 16:31 [16] counter_set_count: number of entries in the counter_set_pointer_table
737     // 0:15  [16] reserved: all zeros
738     const uint32_t bodyHeaderWord2 = static_cast<uint32_t>(counterSetCount) << 16;
739
740     // Body header word 3:
741     // 0:31 [32] counter_set_pointer_table_offset: offset to the counter_set_pointer_table
742     const uint32_t bodyHeaderWord3 =
743                    numeric_cast<uint32_t>(deviceRecordOffsets.size() * uint32_t_size // The size of the
744                                           + bodyHeaderSizeBytes);                    // device records pointer table
745
746     // Body header word 4:
747     // 16:31 [16] categories_count: number of entries in the categories_pointer_table
748     // 0:15  [16] reserved: all zeros
749     const uint32_t bodyHeaderWord4 = static_cast<uint32_t>(categoryCount) << 16;
750
751     // Body header word 3:
752     // 0:31 [32] categories_pointer_table_offset: offset to the categories_pointer_table
753     const uint32_t bodyHeaderWord5 =
754                    numeric_cast<uint32_t>(
755                        deviceRecordOffsets.size() * uint32_t_size +     // The size of the device records
756                        counterSetRecordOffsets.size() * uint32_t_size   // pointer table, plus the size of
757                        +  bodyHeaderSizeBytes);                         // the counter set pointer table
758
759     // Create the body header
760     const uint32_t bodyHeader[bodyHeaderSize]
761     {
762         bodyHeaderWord0, // device_records_count + reserved
763         bodyHeaderWord1, // device_records_pointer_table_offset
764         bodyHeaderWord2, // counter_set_count + reserved
765         bodyHeaderWord3, // counter_set_pointer_table_offset
766         bodyHeaderWord4, // categories_count + reserved
767         bodyHeaderWord5  // categories_pointer_table_offset
768     };
769
770     ARMNN_NO_CONVERSION_WARN_BEGIN
771     // Create the counter directory packet
772     auto counterDirectoryPacketOffset = counterDirectoryPacket.begin();
773     // packet_header
774     std::copy(packetHeader, packetHeader + packetHeaderSize, counterDirectoryPacketOffset);
775     counterDirectoryPacketOffset += packetHeaderSize;
776     // body_header
777     std::copy(bodyHeader, bodyHeader + bodyHeaderSize, counterDirectoryPacketOffset);
778     counterDirectoryPacketOffset += bodyHeaderSize;
779     // device_records_pointer_table
780     std::copy(deviceRecordOffsets.begin(), deviceRecordOffsets.end(), counterDirectoryPacketOffset);
781     counterDirectoryPacketOffset += deviceRecordOffsets.size();
782     // counter_set_pointer_table
783     std::copy(counterSetRecordOffsets.begin(), counterSetRecordOffsets.end(), counterDirectoryPacketOffset);
784     counterDirectoryPacketOffset += counterSetRecordOffsets.size();
785     // category_pointer_table
786     std::copy(categoryRecordOffsets.begin(), categoryRecordOffsets.end(), counterDirectoryPacketOffset);
787     counterDirectoryPacketOffset += categoryRecordOffsets.size();
788     // device_records
789     for (const DeviceRecord& deviceRecord : deviceRecords)
790     {
791         std::copy(deviceRecord.begin(), deviceRecord.end(), counterDirectoryPacketOffset); // device_record
792         counterDirectoryPacketOffset += deviceRecord.size();
793     }
794     // counter_set_records
795     for (const CounterSetRecord& counterSetRecord : counterSetRecords)
796     {
797         std::copy(counterSetRecord.begin(), counterSetRecord.end(), counterDirectoryPacketOffset); // counter_set_record
798         counterDirectoryPacketOffset += counterSetRecord.size();
799     }
800     // category_records
801     for (const CategoryRecord& categoryRecord : categoryRecords)
802     {
803         std::copy(categoryRecord.begin(), categoryRecord.end(), counterDirectoryPacketOffset); // category_record
804         counterDirectoryPacketOffset += categoryRecord.size();
805     }
806     ARMNN_NO_CONVERSION_WARN_END
807
808     // Calculate the total size in bytes of the counter directory packet
809     uint32_t totalSize = numeric_cast<uint32_t>(counterDirectoryPacketSize * uint32_t_size);
810
811     // Reserve space in the buffer for the packet
812     uint32_t reserved = 0;
813     IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
814
815     if (writeBuffer == nullptr || reserved < totalSize)
816     {
817         CancelOperationAndThrow<BufferExhaustion>(
818             writeBuffer,
819             boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
820     }
821
822     // Offset for writing to the buffer
823     uint32_t offset = 0;
824
825     // Write the counter directory packet to the buffer
826     for (uint32_t counterDirectoryPacketWord : counterDirectoryPacket)
827     {
828         WriteUint32(writeBuffer, offset, counterDirectoryPacketWord);
829         offset += numeric_cast<uint32_t>(uint32_t_size);
830     }
831
832     m_BufferManager.Commit(writeBuffer, totalSize);
833 }
834
835 void SendCounterPacket::SendPeriodicCounterCapturePacket(uint64_t timestamp, const IndexValuePairsVector& values)
836 {
837     uint32_t uint16_t_size = sizeof(uint16_t);
838     uint32_t uint32_t_size = sizeof(uint32_t);
839     uint32_t uint64_t_size = sizeof(uint64_t);
840
841     uint32_t packetFamily = 3;
842     uint32_t packetClass = 0;
843     uint32_t packetType = 0;
844     uint32_t headerSize = 2 * uint32_t_size;
845     uint32_t bodySize = uint64_t_size + numeric_cast<uint32_t>(values.size()) * (uint16_t_size + uint32_t_size);
846     uint32_t totalSize = headerSize + bodySize;
847     uint32_t offset = 0;
848     uint32_t reserved = 0;
849
850     IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
851
852     if (writeBuffer == nullptr || reserved < totalSize)
853     {
854         CancelOperationAndThrow<BufferExhaustion>(
855             writeBuffer,
856             boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
857     }
858
859     // Create header.
860     WriteUint32(writeBuffer,
861                 offset,
862                 ((packetFamily & 0x0000003F) << 26) |
863                 ((packetClass  & 0x0000007F) << 19) |
864                 ((packetType   & 0x00000007) << 16));
865     offset += uint32_t_size;
866     WriteUint32(writeBuffer, offset, bodySize);
867
868     // Copy captured Timestamp.
869     offset += uint32_t_size;
870     WriteUint64(writeBuffer, offset, timestamp);
871
872     // Copy selectedCounterIds.
873     offset += uint64_t_size;
874     for (const auto& pair: values)
875     {
876         WriteUint16(writeBuffer, offset, pair.counterId);
877         offset += uint16_t_size;
878         WriteUint32(writeBuffer, offset, pair.counterValue);
879         offset += uint32_t_size;
880     }
881
882     m_BufferManager.Commit(writeBuffer, totalSize);
883 }
884
885 void SendCounterPacket::SendPeriodicCounterSelectionPacket(uint32_t capturePeriod,
886                                                            const std::vector<uint16_t>& selectedCounterIds)
887 {
888     uint32_t uint16_t_size = sizeof(uint16_t);
889     uint32_t uint32_t_size = sizeof(uint32_t);
890
891     uint32_t packetFamily = 0;
892     uint32_t packetId = 4;
893     uint32_t headerSize = 2 * uint32_t_size;
894     uint32_t bodySize = uint32_t_size + numeric_cast<uint32_t>(selectedCounterIds.size()) * uint16_t_size;
895     uint32_t totalSize = headerSize + bodySize;
896     uint32_t offset = 0;
897     uint32_t reserved = 0;
898
899     IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
900
901     if (writeBuffer == nullptr || reserved < totalSize)
902     {
903         CancelOperationAndThrow<BufferExhaustion>(
904             writeBuffer,
905             boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
906     }
907
908     // Create header.
909     WriteUint32(writeBuffer, offset, ((packetFamily & 0x3F) << 26) | ((packetId & 0x3FF) << 16));
910     offset += uint32_t_size;
911     WriteUint32(writeBuffer, offset, bodySize);
912
913     // Copy capturePeriod.
914     offset += uint32_t_size;
915     WriteUint32(writeBuffer, offset, capturePeriod);
916
917     // Copy selectedCounterIds.
918     offset += uint32_t_size;
919     for(const uint16_t& id: selectedCounterIds)
920     {
921         WriteUint16(writeBuffer, offset, id);
922         offset += uint16_t_size;
923     }
924
925     m_BufferManager.Commit(writeBuffer, totalSize);
926 }
927
928 } // namespace profiling
929
930 } // namespace armnn