2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
6 #include "SendCounterPacket.hpp"
7 #include "EncodeVersion.hpp"
9 #include <armnn/Exceptions.hpp>
10 #include <armnn/Conversion.hpp>
11 #include <Processes.hpp>
12 #include <armnn/utility/IgnoreUnused.hpp>
14 #include <boost/format.hpp>
15 #include <boost/numeric/conversion/cast.hpp>
25 using boost::numeric_cast;
27 const unsigned int SendCounterPacket::PIPE_MAGIC;
29 void SendCounterPacket::SendStreamMetaDataPacket()
31 std::string info(GetSoftwareInfo());
32 std::string hardwareVersion(GetHardwareVersion());
33 std::string softwareVersion(GetSoftwareVersion());
34 std::string processName = GetProcessName().substr(0, 60);
36 uint32_t infoSize = numeric_cast<uint32_t>(info.size()) > 0 ? numeric_cast<uint32_t>(info.size()) + 1 : 0;
37 uint32_t hardwareVersionSize = numeric_cast<uint32_t>(hardwareVersion.size()) > 0 ?
38 numeric_cast<uint32_t>(hardwareVersion.size()) + 1 : 0;
39 uint32_t softwareVersionSize = numeric_cast<uint32_t>(softwareVersion.size()) > 0 ?
40 numeric_cast<uint32_t>(softwareVersion.size()) + 1 : 0;
41 uint32_t processNameSize = numeric_cast<uint32_t>(processName.size()) > 0 ?
42 numeric_cast<uint32_t>(processName.size()) + 1 : 0;
44 uint32_t sizeUint32 = numeric_cast<uint32_t>(sizeof(uint32_t));
46 uint32_t headerSize = 2 * sizeUint32;
47 uint32_t bodySize = 10 * sizeUint32;
48 uint32_t packetVersionCountSize = sizeUint32;
51 // Stream metadata packet (packet family=0; packet id=0)
52 // Connection Acknowledged packet (packet family=0, packet id=1)
53 // Counter Directory packet (packet family=0; packet id=2)
54 // Request Counter Directory packet (packet family=0, packet id=3)
55 // Periodic Counter Selection packet (packet family=0, packet id=4)
56 // Periodic Counter Capture packet (packet family=1, packet class=0, type=0)
57 uint32_t packetVersionEntries = 6;
59 uint32_t payloadSize = numeric_cast<uint32_t>(infoSize + hardwareVersionSize + softwareVersionSize +
60 processNameSize + packetVersionCountSize +
61 (packetVersionEntries * 2 * sizeUint32));
63 uint32_t totalSize = headerSize + bodySize + payloadSize;
65 uint32_t reserved = 0;
67 IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
69 if (writeBuffer == nullptr || reserved < totalSize)
71 CancelOperationAndThrow<BufferExhaustion>(
73 boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
80 WriteUint32(writeBuffer, offset, 0);
82 WriteUint32(writeBuffer, offset, totalSize - headerSize);
87 WriteUint32(writeBuffer, offset, PIPE_MAGIC); // pipe_magic
89 WriteUint32(writeBuffer, offset, EncodeVersion(1, 0, 0)); // stream_metadata_version
91 WriteUint32(writeBuffer, offset, MAX_METADATA_PACKET_LENGTH); // max_data_length
93 int pid = armnnUtils::Processes::GetCurrentId();
94 WriteUint32(writeBuffer, offset, numeric_cast<uint32_t>(pid)); // pid
96 uint32_t poolOffset = bodySize;
97 WriteUint32(writeBuffer, offset, infoSize ? poolOffset : 0); // offset_info
99 poolOffset += infoSize;
100 WriteUint32(writeBuffer, offset, hardwareVersionSize ? poolOffset : 0); // offset_hw_version
101 offset += sizeUint32;
102 poolOffset += hardwareVersionSize;
103 WriteUint32(writeBuffer, offset, softwareVersionSize ? poolOffset : 0); // offset_sw_version
104 offset += sizeUint32;
105 poolOffset += softwareVersionSize;
106 WriteUint32(writeBuffer, offset, processNameSize ? poolOffset : 0); // offset_process_name
107 offset += sizeUint32;
108 poolOffset += processNameSize;
109 WriteUint32(writeBuffer, offset, packetVersionEntries ? poolOffset : 0); // offset_packet_version_table
110 offset += sizeUint32;
111 WriteUint32(writeBuffer, offset, 0); // reserved
112 offset += sizeUint32;
118 memcpy(&writeBuffer->GetWritableData()[offset], info.c_str(), infoSize);
122 if (hardwareVersionSize)
124 memcpy(&writeBuffer->GetWritableData()[offset], hardwareVersion.c_str(), hardwareVersionSize);
125 offset += hardwareVersionSize;
128 if (softwareVersionSize)
130 memcpy(&writeBuffer->GetWritableData()[offset], softwareVersion.c_str(), softwareVersionSize);
131 offset += softwareVersionSize;
136 memcpy(&writeBuffer->GetWritableData()[offset], processName.c_str(), processNameSize);
137 offset += processNameSize;
140 if (packetVersionEntries)
142 // Packet Version Count
143 WriteUint32(writeBuffer, offset, packetVersionEntries << 16);
145 // Packet Version Entries
146 uint32_t packetFamily = 0;
147 uint32_t packetId = 0;
149 offset += sizeUint32;
150 for (uint32_t i = 0; i < packetVersionEntries - 1; ++i)
152 WriteUint32(writeBuffer, offset, ((packetFamily & 0x3F) << 26) | ((packetId++ & 0x3FF) << 16));
153 offset += sizeUint32;
154 WriteUint32(writeBuffer, offset, EncodeVersion(1, 0, 0));
155 offset += sizeUint32;
161 WriteUint32(writeBuffer, offset, ((packetFamily & 0x3F) << 26) | ((packetId & 0x3FF) << 16));
162 offset += sizeUint32;
163 WriteUint32(writeBuffer, offset, EncodeVersion(1, 0, 0));
168 CancelOperationAndThrow<RuntimeException>(writeBuffer, "Error processing packet.");
171 m_BufferManager.Commit(writeBuffer, totalSize, false);
174 bool SendCounterPacket::CreateCategoryRecord(const CategoryPtr& category,
175 const Counters& counters,
176 CategoryRecord& categoryRecord,
177 std::string& errorMessage)
179 using namespace boost::numeric;
181 BOOST_ASSERT(category);
183 const std::string& categoryName = category->m_Name;
184 BOOST_ASSERT(!categoryName.empty());
186 // Remove any duplicate counters
187 std::vector<uint16_t> categoryCounters;
188 for (size_t counterIndex = 0; counterIndex < category->m_Counters.size(); ++counterIndex)
190 uint16_t counterUid = category->m_Counters.at(counterIndex);
191 auto it = counters.find(counterUid);
192 if (it == counters.end())
194 errorMessage = boost::str(boost::format("Counter (%1%) not found in category (%2%)")
195 % counterUid % category->m_Name );
199 const CounterPtr& counter = it->second;
201 if (counterUid == counter->m_MaxCounterUid)
203 categoryCounters.emplace_back(counterUid);
206 if (categoryCounters.empty())
208 errorMessage = boost::str(boost::format("No valid counters found in category (%1%)")% categoryName);
213 size_t uint32_t_size = sizeof(uint32_t);
215 // Category record word 1:
216 // 16:31 [16] event_count: number of events belonging to this category
217 // 0:15 [16] reserved: all zeros
218 uint32_t categoryRecordWord1 = static_cast<uint32_t>(categoryCounters.size()) << 16;
220 // Category record word 2:
221 // 0:31 [32] event_pointer_table_offset: offset from the beginning of the category data pool to
222 // the event_pointer_table
223 uint32_t categoryRecordWord2 = 0; // The offset is always zero here, as the event pointer table field is always
224 // the first item in the pool
226 // Convert the device name into a SWTrace namestring
227 std::vector<uint32_t> categoryNameBuffer;
228 if (!StringToSwTraceString<SwTraceNameCharPolicy>(categoryName, categoryNameBuffer))
230 errorMessage = boost::str(boost::format("Cannot convert the name of category (%1%) to an SWTrace namestring")
235 // Process the event records
236 size_t counterCount = categoryCounters.size();
237 std::vector<EventRecord> eventRecords(counterCount);
238 std::vector<uint32_t> eventRecordOffsets(counterCount, 0);
239 size_t eventRecordsSize = 0;
240 uint32_t eventRecordsOffset =
241 numeric_cast<uint32_t>((eventRecords.size() + categoryNameBuffer.size()) * uint32_t_size);
242 for (size_t counterIndex = 0, eventRecordIndex = 0, eventRecordOffsetIndex = 0;
243 counterIndex < counterCount;
244 counterIndex++, eventRecordIndex++, eventRecordOffsetIndex++)
246 uint16_t counterUid = categoryCounters.at(counterIndex);
247 auto it = counters.find(counterUid);
248 const CounterPtr& counter = it->second;
250 EventRecord& eventRecord = eventRecords.at(eventRecordIndex);
251 if (!CreateEventRecord(counter, eventRecord, errorMessage))
256 // Update the total size in words of the event records
257 eventRecordsSize += eventRecord.size();
259 // Add the event record offset to the event pointer table offset field
260 eventRecordOffsets[eventRecordOffsetIndex] = eventRecordsOffset;
261 eventRecordsOffset += numeric_cast<uint32_t>(eventRecord.size() * uint32_t_size);
264 // Category record word 3:
265 // 0:31 [32] name_offset (offset from the beginning of the category data pool to the name field)
266 uint32_t categoryRecordWord3 = numeric_cast<uint32_t>(eventRecordOffsets.size() * uint32_t_size);
268 // Calculate the size in words of the category record
269 size_t categoryRecordSize = 3u + // The size of the fixed part (device + counter_set + event_count + reserved +
270 // event_pointer_table_offset + name_offset)
271 eventRecordOffsets.size() + // The size of the variable part (the event pointer table +
272 categoryNameBuffer.size() + // and the category name including the null-terminator +
273 eventRecordsSize; // the event records)
275 // Allocate the necessary space for the category record
276 categoryRecord.resize(categoryRecordSize);
278 ARMNN_NO_CONVERSION_WARN_BEGIN
279 // Create the category record
280 categoryRecord[0] = categoryRecordWord1; // event_count + reserved
281 categoryRecord[1] = categoryRecordWord2; // event_pointer_table_offset
282 categoryRecord[2] = categoryRecordWord3; // name_offset
283 auto offset = categoryRecord.begin() + 3u;
284 std::copy(eventRecordOffsets.begin(), eventRecordOffsets.end(), offset); // event_pointer_table
285 offset += eventRecordOffsets.size();
286 std::copy(categoryNameBuffer.begin(), categoryNameBuffer.end(), offset); // name
287 offset += categoryNameBuffer.size();
288 for (const EventRecord& eventRecord : eventRecords)
290 std::copy(eventRecord.begin(), eventRecord.end(), offset); // event_record
291 offset += eventRecord.size();
293 ARMNN_NO_CONVERSION_WARN_END
298 bool SendCounterPacket::CreateDeviceRecord(const DevicePtr& device,
299 DeviceRecord& deviceRecord,
300 std::string& errorMessage)
302 BOOST_ASSERT(device);
304 uint16_t deviceUid = device->m_Uid;
305 const std::string& deviceName = device->m_Name;
306 uint16_t deviceCores = device->m_Cores;
308 BOOST_ASSERT(!deviceName.empty());
310 // Device record word 0:
311 // 16:31 [16] uid: the unique identifier for the device
312 // 0:15 [16] cores: the number of individual streams of counters for one or more cores of some device
313 uint32_t deviceRecordWord0 = (static_cast<uint32_t>(deviceUid) << 16) |
314 (static_cast<uint32_t>(deviceCores));
316 // Device record word 1:
317 // 0:31 [32] name_offset: offset from the beginning of the device record pool to the name field
318 uint32_t deviceRecordWord1 = 0; // The offset is always zero here, as the name field is always
319 // the first (and only) item in the pool
321 // Convert the device name into a SWTrace string
322 std::vector<uint32_t> deviceNameBuffer;
323 if (!StringToSwTraceString<SwTraceCharPolicy>(deviceName, deviceNameBuffer))
325 errorMessage = boost::str(boost::format("Cannot convert the name of device %1% (%2%) to an SWTrace string")
331 // Calculate the size in words of the device record
332 size_t deviceRecordSize = 2u + // The size of the fixed part (uid + cores + name_offset)
333 deviceNameBuffer.size(); // The size of the variable part (the device name including
334 // the null-terminator)
336 // Allocate the necessary space for the device record
337 deviceRecord.resize(deviceRecordSize);
339 // Create the device record
340 deviceRecord[0] = deviceRecordWord0; // uid + core
341 deviceRecord[1] = deviceRecordWord1; // name_offset
342 auto offset = deviceRecord.begin() + 2u;
343 std::copy(deviceNameBuffer.begin(), deviceNameBuffer.end(), offset); // name
348 bool SendCounterPacket::CreateCounterSetRecord(const CounterSetPtr& counterSet,
349 CounterSetRecord& counterSetRecord,
350 std::string& errorMessage)
352 BOOST_ASSERT(counterSet);
354 uint16_t counterSetUid = counterSet->m_Uid;
355 const std::string& counterSetName = counterSet->m_Name;
356 uint16_t counterSetCount = counterSet->m_Count;
358 BOOST_ASSERT(!counterSetName.empty());
360 // Counter set record word 0:
361 // 16:31 [16] uid: the unique identifier for the counter_set
362 // 0:15 [16] count: the number of counters which can be active in this set at any one time
363 uint32_t counterSetRecordWord0 = (static_cast<uint32_t>(counterSetUid) << 16) |
364 (static_cast<uint32_t>(counterSetCount));
366 // Counter set record word 1:
367 // 0:31 [32] name_offset: offset from the beginning of the counter set pool to the name field
368 uint32_t counterSetRecordWord1 = 0; // The offset is always zero here, as the name field is always
369 // the first (and only) item in the pool
371 // Convert the device name into a SWTrace namestring
372 std::vector<uint32_t> counterSetNameBuffer;
373 if (!StringToSwTraceString<SwTraceNameCharPolicy>(counterSet->m_Name, counterSetNameBuffer))
375 errorMessage = boost::str(boost::format("Cannot convert the name of counter set %1% (%2%) to "
376 "an SWTrace namestring")
382 // Calculate the size in words of the counter set record
383 size_t counterSetRecordSize = 2u + // The size of the fixed part (uid + cores + name_offset)
384 counterSetNameBuffer.size(); // The size of the variable part (the counter set name
385 // including the null-terminator)
387 // Allocate the space for the counter set record
388 counterSetRecord.resize(counterSetRecordSize);
390 // Create the counter set record
391 counterSetRecord[0] = counterSetRecordWord0; // uid + core
392 counterSetRecord[1] = counterSetRecordWord1; // name_offset
393 auto offset = counterSetRecord.begin() + 2u;
394 std::copy(counterSetNameBuffer.begin(), counterSetNameBuffer.end(), offset); // name
399 bool SendCounterPacket::CreateEventRecord(const CounterPtr& counter,
400 EventRecord& eventRecord,
401 std::string& errorMessage)
403 using namespace boost::numeric;
405 BOOST_ASSERT(counter);
407 uint16_t counterUid = counter->m_Uid;
408 uint16_t maxCounterUid = counter->m_MaxCounterUid;
409 uint16_t deviceUid = counter->m_DeviceUid;
410 uint16_t counterSetUid = counter->m_CounterSetUid;
411 uint16_t counterClass = counter->m_Class;
412 uint16_t counterInterpolation = counter->m_Interpolation;
413 double counterMultiplier = counter->m_Multiplier;
414 const std::string& counterName = counter->m_Name;
415 const std::string& counterDescription = counter->m_Description;
416 const std::string& counterUnits = counter->m_Units;
418 BOOST_ASSERT(counterClass == 0 || counterClass == 1);
419 BOOST_ASSERT(counterInterpolation == 0 || counterInterpolation == 1);
420 BOOST_ASSERT(counterMultiplier);
423 size_t uint32_t_size = sizeof(uint32_t);
425 // Event record word 0:
426 // 16:31 [16] max_counter_uid: if the device this event is associated with has more than one core and there
427 // is one of these counters per core this value will be set to
428 // (counter_uid + cores (from device_record)) - 1.
429 // If there is only a single core then this value will be the same as
430 // the counter_uid value
431 // 0:15 [16] count_uid: unique ID for the counter. Must be unique across all counters in all categories
432 uint32_t eventRecordWord0 = (static_cast<uint32_t>(maxCounterUid) << 16) |
433 (static_cast<uint32_t>(counterUid));
435 // Event record word 1:
436 // 16:31 [16] device: UID of the device this event is associated with. Set to zero if the event is NOT
437 // associated with a device
438 // 0:15 [16] counter_set: UID of the counter_set this event is associated with. Set to zero if the event
439 // is NOT associated with a counter_set
440 uint32_t eventRecordWord1 = (static_cast<uint32_t>(deviceUid) << 16) |
441 (static_cast<uint32_t>(counterSetUid));
443 // Event record word 2:
444 // 16:31 [16] class: type describing how to treat each data point in a stream of data points
445 // 0:15 [16] interpolation: type describing how to interpolate each data point in a stream of data points
446 uint32_t eventRecordWord2 = (static_cast<uint32_t>(counterClass) << 16) |
447 (static_cast<uint32_t>(counterInterpolation));
449 // Event record word 3-4:
450 // 0:63 [64] multiplier: internal data stream is represented as integer values, this allows scaling of
451 // those values as if they are fixed point numbers. Zero is not a valid value
452 uint32_t multiplier[2] = { 0u, 0u };
453 BOOST_ASSERT(sizeof(counterMultiplier) == sizeof(multiplier));
454 std::memcpy(multiplier, &counterMultiplier, sizeof(multiplier));
455 uint32_t eventRecordWord3 = multiplier[0];
456 uint32_t eventRecordWord4 = multiplier[1];
458 // Event record word 5:
459 // 0:31 [32] name_offset: offset from the beginning of the event record pool to the name field
460 uint32_t eventRecordWord5 = 0; // The offset is always zero here, as the name field is always
461 // the first item in the pool
463 // Convert the counter name into a SWTrace string
464 std::vector<uint32_t> counterNameBuffer;
465 if (!StringToSwTraceString<SwTraceCharPolicy>(counterName, counterNameBuffer))
467 errorMessage = boost::str(boost::format("Cannot convert the name of counter %1% (name: %2%) "
468 "to an SWTrace string")
474 // Event record word 6:
475 // 0:31 [32] description_offset: offset from the beginning of the event record pool to the description field
476 // The size of the name buffer in bytes
477 uint32_t eventRecordWord6 = numeric_cast<uint32_t>(counterNameBuffer.size() * uint32_t_size);
479 // Convert the counter description into a SWTrace string
480 std::vector<uint32_t> counterDescriptionBuffer;
481 if (!StringToSwTraceString<SwTraceCharPolicy>(counterDescription, counterDescriptionBuffer))
483 errorMessage = boost::str(boost::format("Cannot convert the description of counter %1% (description: %2%) "
484 "to an SWTrace string")
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 uint32_t eventRecordWord7 = includeUnits ?
497 numeric_cast<uint32_t>(counterDescriptionBuffer.size() * uint32_t_size) :
500 // Convert the counter units into a SWTrace namestring (optional)
501 std::vector<uint32_t> counterUnitsBuffer;
504 // Convert the counter units into a SWTrace namestring
505 if (!StringToSwTraceString<SwTraceNameCharPolicy>(counterUnits, counterUnitsBuffer))
507 errorMessage = boost::str(boost::format("Cannot convert the units of counter %1% (units: %2%) "
508 "to an SWTrace string")
515 // Calculate the size in words of the event record
516 size_t eventRecordSize = 8u + // The size of the fixed part (counter_uid + max_counter_uid + device +
517 // counter_set + class + interpolation +
518 // multiplier + name_offset + description_offset +
520 counterNameBuffer.size() + // The size of the variable part (the counter name,
521 counterDescriptionBuffer.size() + // description and units including the null-terminator)
522 counterUnitsBuffer.size();
524 // Allocate the space for the event record
525 eventRecord.resize(eventRecordSize);
527 ARMNN_NO_CONVERSION_WARN_BEGIN
528 // Create the event record
529 eventRecord[0] = eventRecordWord0; // max_counter_uid + counter_uid
530 eventRecord[1] = eventRecordWord1; // device + counter_set
531 eventRecord[2] = eventRecordWord2; // class + interpolation
532 eventRecord[3] = eventRecordWord3; // multiplier
533 eventRecord[4] = eventRecordWord4; // multiplier
534 eventRecord[5] = eventRecordWord5; // name_offset
535 eventRecord[6] = eventRecordWord6; // description_offset
536 eventRecord[7] = eventRecordWord7; // units_offset
537 auto offset = eventRecord.begin() + 8u;
538 std::copy(counterNameBuffer.begin(), counterNameBuffer.end(), offset); // name
539 offset += counterNameBuffer.size();
540 std::copy(counterDescriptionBuffer.begin(), counterDescriptionBuffer.end(), offset); // description
543 offset += counterDescriptionBuffer.size();
544 std::copy(counterUnitsBuffer.begin(), counterUnitsBuffer.end(), offset); // units
546 ARMNN_NO_CONVERSION_WARN_END
551 void SendCounterPacket::SendCounterDirectoryPacket(const ICounterDirectory& counterDirectory)
553 using namespace boost::numeric;
555 // Get the amount of data that needs to be put into the packet
556 uint16_t categoryCount = counterDirectory.GetCategoryCount();
557 uint16_t deviceCount = counterDirectory.GetDeviceCount();
558 uint16_t counterSetCount = counterDirectory.GetCounterSetCount();
561 size_t uint32_t_size = sizeof(uint32_t);
562 size_t packetHeaderSize = 2u;
563 size_t bodyHeaderSize = 6u;
565 // Initialize the offset for the pointer tables
566 uint32_t pointerTableOffset = 0;
572 // Process device records
573 std::vector<DeviceRecord> deviceRecords(deviceCount);
574 const Devices& devices = counterDirectory.GetDevices();
575 std::vector<uint32_t> deviceRecordOffsets(deviceCount, 0); // device_records_pointer_table
576 size_t deviceRecordsSize = 0;
577 size_t deviceIndex = 0;
578 size_t deviceRecordOffsetIndex = 0;
579 for (auto it = devices.begin(); it != devices.end(); it++)
581 const DevicePtr& device = it->second;
582 DeviceRecord& deviceRecord = deviceRecords.at(deviceIndex);
584 std::string errorMessage;
585 if (!CreateDeviceRecord(device, deviceRecord, errorMessage))
587 CancelOperationAndThrow<RuntimeException>(errorMessage);
590 // Update the total size in words of the device records
591 deviceRecordsSize += deviceRecord.size();
593 // Add the device record offset to the device records pointer table offset field
594 deviceRecordOffsets[deviceRecordOffsetIndex] = pointerTableOffset;
595 pointerTableOffset += numeric_cast<uint32_t>(deviceRecord.size() * uint32_t_size);
598 deviceRecordOffsetIndex++;
601 // -------------------
602 // Counter set records
603 // -------------------
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 for (auto it = counterSets.begin(); it != counterSets.end(); it++)
614 const CounterSetPtr& counterSet = it->second;
615 CounterSetRecord& counterSetRecord = counterSetRecords.at(counterSetIndex);
617 std::string errorMessage;
618 if (!CreateCounterSetRecord(counterSet, counterSetRecord, errorMessage))
620 CancelOperationAndThrow<RuntimeException>(errorMessage);
623 // Update the total size in words of the counter set records
624 counterSetRecordsSize += counterSetRecord.size();
626 // Add the counter set record offset to the counter set records pointer table offset field
627 counterSetRecordOffsets[counterSetRecordOffsetIndex] = pointerTableOffset;
628 pointerTableOffset += numeric_cast<uint32_t>(counterSetRecord.size() * uint32_t_size);
631 counterSetRecordOffsetIndex++;
638 // Process category records
639 std::vector<CategoryRecord> categoryRecords(categoryCount);
640 const Categories& categories = counterDirectory.GetCategories();
641 std::vector<uint32_t> categoryRecordOffsets(categoryCount, 0); // category_records_pointer_table
642 size_t categoryRecordsSize = 0;
643 size_t categoryIndex = 0;
644 size_t categoryRecordOffsetIndex = 0;
645 for (auto it = categories.begin(); it != categories.end(); it++)
647 const CategoryPtr& category = *it;
648 CategoryRecord& categoryRecord = categoryRecords.at(categoryIndex);
650 std::string errorMessage;
651 if (!CreateCategoryRecord(category, counterDirectory.GetCounters(), categoryRecord, errorMessage))
653 CancelOperationAndThrow<RuntimeException>(errorMessage);
656 // Update the total size in words of the category records
657 categoryRecordsSize += categoryRecord.size();
659 // Add the category record offset to the category records pointer table offset field
660 categoryRecordOffsets[categoryRecordOffsetIndex] = pointerTableOffset;
661 pointerTableOffset += numeric_cast<uint32_t>(categoryRecord.size() * uint32_t_size);
664 categoryRecordOffsetIndex++;
669 // Calculate the length in words of the counter directory packet's data (excludes the packet header size)
670 size_t counterDirectoryPacketDataLength =
671 bodyHeaderSize + // The size of the body header
672 deviceRecordOffsets.size() + // The size of the device records pointer table
673 counterSetRecordOffsets.size() + // The size of counter set pointer table
674 categoryRecordOffsets.size() + // The size of category records pointer table
675 deviceRecordsSize + // The total size of the device records
676 counterSetRecordsSize + // The total size of the counter set records
677 categoryRecordsSize; // The total size of the category records
679 // Calculate the size in words of the counter directory packet (the data length plus the packet header size)
680 size_t counterDirectoryPacketSize = packetHeaderSize + // The size of the packet header
681 counterDirectoryPacketDataLength; // The data length
684 // Allocate the necessary space for the counter directory packet
685 std::vector<uint32_t> counterDirectoryPacket(counterDirectoryPacketSize, 0);
691 // Packet header word 0:
692 // 26:31 [6] packet_family: control Packet Family
693 // 16:25 [10] packet_id: packet identifier
694 // 8:15 [8] reserved: all zeros
695 // 0:7 [8] reserved: all zeros
696 uint32_t packetFamily = 0;
697 uint32_t packetId = 2;
698 uint32_t packetHeaderWord0 = ((packetFamily & 0x3F) << 26) | ((packetId & 0x3FF) << 16);
700 // Packet header word 1:
701 // 0:31 [32] data_length: length of data, in bytes
702 uint32_t packetHeaderWord1 = numeric_cast<uint32_t>(counterDirectoryPacketDataLength * uint32_t_size);
704 // Create the packet header
705 uint32_t packetHeader[2]
707 packetHeaderWord0, // packet_family + packet_id + reserved + reserved
708 packetHeaderWord1 // data_length
715 // Body header word 0:
716 // 16:31 [16] device_records_count: number of entries in the device_records_pointer_table
717 // 0:15 [16] reserved: all zeros
718 uint32_t bodyHeaderWord0 = static_cast<uint32_t>(deviceCount) << 16;
720 // Body header word 1:
721 // 0:31 [32] device_records_pointer_table_offset: offset to the device_records_pointer_table
722 uint32_t bodyHeaderWord1 = 0; // The offset is always zero here, as the device record pointer table field is always
723 // the first item in the pool
725 // Body header word 2:
726 // 16:31 [16] counter_set_count: number of entries in the counter_set_pointer_table
727 // 0:15 [16] reserved: all zeros
728 uint32_t bodyHeaderWord2 = static_cast<uint32_t>(counterSetCount) << 16;
730 // Body header word 3:
731 // 0:31 [32] counter_set_pointer_table_offset: offset to the counter_set_pointer_table
732 uint32_t bodyHeaderWord3 =
733 numeric_cast<uint32_t>(deviceRecordOffsets.size() * uint32_t_size); // The size of the device records
737 // Body header word 4:
738 // 16:31 [16] categories_count: number of entries in the categories_pointer_table
739 // 0:15 [16] reserved: all zeros
740 uint32_t bodyHeaderWord4 = static_cast<uint32_t>(categoryCount) << 16;
742 // Body header word 3:
743 // 0:31 [32] categories_pointer_table_offset: offset to the categories_pointer_table
744 uint32_t bodyHeaderWord5 =
745 numeric_cast<uint32_t>(deviceRecordOffsets.size() * uint32_t_size + // The size of the device records
746 counterSetRecordOffsets.size() * uint32_t_size); // pointer table, plus the size of
747 // the counter set pointer table
749 // Create the body header
750 uint32_t bodyHeader[6]
752 bodyHeaderWord0, // device_records_count + reserved
753 bodyHeaderWord1, // device_records_pointer_table_offset
754 bodyHeaderWord2, // counter_set_count + reserved
755 bodyHeaderWord3, // counter_set_pointer_table_offset
756 bodyHeaderWord4, // categories_count + reserved
757 bodyHeaderWord5 // categories_pointer_table_offset
760 ARMNN_NO_CONVERSION_WARN_BEGIN
761 // Create the counter directory packet
762 auto counterDirectoryPacketOffset = counterDirectoryPacket.begin();
764 std::copy(packetHeader, packetHeader + packetHeaderSize, counterDirectoryPacketOffset);
765 counterDirectoryPacketOffset += packetHeaderSize;
767 std::copy(bodyHeader, bodyHeader + bodyHeaderSize, counterDirectoryPacketOffset);
768 counterDirectoryPacketOffset += bodyHeaderSize;
769 // device_records_pointer_table
770 std::copy(deviceRecordOffsets.begin(), deviceRecordOffsets.end(), counterDirectoryPacketOffset);
771 counterDirectoryPacketOffset += deviceRecordOffsets.size();
772 // counter_set_pointer_table
773 std::copy(counterSetRecordOffsets.begin(), counterSetRecordOffsets.end(), counterDirectoryPacketOffset);
774 counterDirectoryPacketOffset += counterSetRecordOffsets.size();
775 // category_pointer_table
776 std::copy(categoryRecordOffsets.begin(), categoryRecordOffsets.end(), counterDirectoryPacketOffset);
777 counterDirectoryPacketOffset += categoryRecordOffsets.size();
779 for (const DeviceRecord& deviceRecord : deviceRecords)
781 std::copy(deviceRecord.begin(), deviceRecord.end(), counterDirectoryPacketOffset); // device_record
782 counterDirectoryPacketOffset += deviceRecord.size();
784 // counter_set_records
785 for (const CounterSetRecord& counterSetRecord : counterSetRecords)
787 std::copy(counterSetRecord.begin(), counterSetRecord.end(), counterDirectoryPacketOffset); // counter_set_record
788 counterDirectoryPacketOffset += counterSetRecord.size();
791 for (const CategoryRecord& categoryRecord : categoryRecords)
793 std::copy(categoryRecord.begin(), categoryRecord.end(), counterDirectoryPacketOffset); // category_record
794 counterDirectoryPacketOffset += categoryRecord.size();
796 ARMNN_NO_CONVERSION_WARN_END
798 // Calculate the total size in bytes of the counter directory packet
799 uint32_t totalSize = numeric_cast<uint32_t>(counterDirectoryPacketSize * uint32_t_size);
801 // Reserve space in the buffer for the packet
802 uint32_t reserved = 0;
803 IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
805 if (writeBuffer == nullptr || reserved < totalSize)
807 CancelOperationAndThrow<BufferExhaustion>(
809 boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
812 // Offset for writing to the buffer
815 // Write the counter directory packet to the buffer
816 for (uint32_t counterDirectoryPacketWord : counterDirectoryPacket)
818 WriteUint32(writeBuffer, offset, counterDirectoryPacketWord);
819 offset += numeric_cast<uint32_t>(uint32_t_size);
822 m_BufferManager.Commit(writeBuffer, totalSize);
825 void SendCounterPacket::SendPeriodicCounterCapturePacket(uint64_t timestamp, const IndexValuePairsVector& values)
827 uint32_t uint16_t_size = sizeof(uint16_t);
828 uint32_t uint32_t_size = sizeof(uint32_t);
829 uint32_t uint64_t_size = sizeof(uint64_t);
831 uint32_t packetFamily = 3;
832 uint32_t packetClass = 0;
833 uint32_t packetType = 0;
834 uint32_t headerSize = 2 * uint32_t_size;
835 uint32_t bodySize = uint64_t_size + numeric_cast<uint32_t>(values.size()) * (uint16_t_size + uint32_t_size);
836 uint32_t totalSize = headerSize + bodySize;
838 uint32_t reserved = 0;
840 IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
842 if (writeBuffer == nullptr || reserved < totalSize)
844 CancelOperationAndThrow<BufferExhaustion>(
846 boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
850 WriteUint32(writeBuffer,
852 ((packetFamily & 0x0000003F) << 26) |
853 ((packetClass & 0x0000007F) << 19) |
854 ((packetType & 0x00000007) << 16));
855 offset += uint32_t_size;
856 WriteUint32(writeBuffer, offset, bodySize);
858 // Copy captured Timestamp.
859 offset += uint32_t_size;
860 WriteUint64(writeBuffer, offset, timestamp);
862 // Copy selectedCounterIds.
863 offset += uint64_t_size;
864 for (const auto& pair: values)
866 WriteUint16(writeBuffer, offset, pair.counterId);
867 offset += uint16_t_size;
868 WriteUint32(writeBuffer, offset, pair.counterValue);
869 offset += uint32_t_size;
872 m_BufferManager.Commit(writeBuffer, totalSize);
875 void SendCounterPacket::SendPeriodicCounterSelectionPacket(uint32_t capturePeriod,
876 const std::vector<uint16_t>& selectedCounterIds)
878 uint32_t uint16_t_size = sizeof(uint16_t);
879 uint32_t uint32_t_size = sizeof(uint32_t);
881 uint32_t packetFamily = 0;
882 uint32_t packetId = 4;
883 uint32_t headerSize = 2 * uint32_t_size;
884 uint32_t bodySize = uint32_t_size + numeric_cast<uint32_t>(selectedCounterIds.size()) * uint16_t_size;
885 uint32_t totalSize = headerSize + bodySize;
887 uint32_t reserved = 0;
889 IPacketBufferPtr writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
891 if (writeBuffer == nullptr || reserved < totalSize)
893 CancelOperationAndThrow<BufferExhaustion>(
895 boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.") % totalSize));
899 WriteUint32(writeBuffer, offset, ((packetFamily & 0x3F) << 26) | ((packetId & 0x3FF) << 16));
900 offset += uint32_t_size;
901 WriteUint32(writeBuffer, offset, bodySize);
903 // Copy capturePeriod.
904 offset += uint32_t_size;
905 WriteUint32(writeBuffer, offset, capturePeriod);
907 // Copy selectedCounterIds.
908 offset += uint32_t_size;
909 for(const uint16_t& id: selectedCounterIds)
911 WriteUint16(writeBuffer, offset, id);
912 offset += uint16_t_size;
915 m_BufferManager.Commit(writeBuffer, totalSize);
918 } // namespace profiling