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