blob: e20f5402c6f8f11da13182d116b4c9a94e2d1c5d [file] [log] [blame]
Finn Williams15db7452019-10-15 14:22:13 +01001//
2// Copyright © 2019 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
Keith Davise394bd92019-12-02 15:12:19 +00005#include "DirectoryCaptureCommandHandler.hpp"
6
7#include <armnn/BackendId.hpp>
8#include "ProfilingUtils.hpp"
Finn Williams15db7452019-10-15 14:22:13 +01009
Finn Williamse63a0262019-10-22 10:30:49 +010010#include <atomic>
Keith Davis3201eea2019-10-24 17:30:41 +010011#include <iostream>
Finn Williams15db7452019-10-15 14:22:13 +010012
13namespace armnn
14{
15
Keith Davis3201eea2019-10-24 17:30:41 +010016namespace profiling
Finn Williams15db7452019-10-15 14:22:13 +010017{
18
19// Utils
20uint32_t uint16_t_size = sizeof(uint16_t);
21uint32_t uint32_t_size = sizeof(uint32_t);
22
23void DirectoryCaptureCommandHandler::ParseData(const armnn::profiling::Packet& packet)
24{
25 uint16_t categoryRecordCount;
26 uint16_t counterSetRecordCount;
27 uint16_t deviceRecordCount;
28
29 uint32_t offset = 0;
30
31 if (packet.GetLength() < 8)
32 {
33 std::cout << "Counter directory packet received." << std::endl;
34 return;
35 }
36
Keith Davis3201eea2019-10-24 17:30:41 +010037 const unsigned char* data = packet.GetData();
Finn Williams15db7452019-10-15 14:22:13 +010038 // Body header word 0:
39 // 0:15 [16] reserved: all zeros
40 offset += uint16_t_size;
41 // 16:31 [16] device_records_count: number of entries in the device_records_pointer_table
42 deviceRecordCount = profiling::ReadUint16(data, offset);
43 offset += uint16_t_size;
44
45 // Body header word 1:
46 // 0:31 [32] device_records_pointer_table_offset: offset to the device_records_pointer_table
47 // The offset is always zero here, as the device record pointer table field is always the first item in the pool
Finn Williamsd44815f2020-05-01 13:25:55 +010048 const uint32_t deviceRecordsPointerTableOffset = profiling::ReadUint32(data, offset);
Finn Williams15db7452019-10-15 14:22:13 +010049 offset += uint32_t_size;
50
51 // Body header word 2:
52 // 0:15 [16] reserved: all zeros
53 offset += uint16_t_size;
54 // 16:31 [16] counter_set_count: number of entries in the counter_set_pointer_table
55 counterSetRecordCount = profiling::ReadUint16(data, offset);
56 offset += uint16_t_size;
57
58 // Body header word 3:
59 // 0:31 [32] counter_set_pointer_table_offset: offset to the counter_set_pointer_table
Finn Williamsd44815f2020-05-01 13:25:55 +010060 const uint32_t counterPointerTableSetOffset = profiling::ReadUint32(data, offset);
Finn Williams15db7452019-10-15 14:22:13 +010061 offset += uint32_t_size;
62
63 // Body header word 4:
64 // 0:15 [16] reserved: all zeros
65 offset += uint16_t_size;
66 // 16:31 [16] categories_count: number of entries in the categories_pointer_table
67 categoryRecordCount = profiling::ReadUint16(data, offset);
68 offset += uint16_t_size;
69
70 // Body header word 5:
71 // 0:31 [32] categories_pointer_table_offset: offset to the categories_pointer_table
Finn Williamsd44815f2020-05-01 13:25:55 +010072 const uint32_t categoriesPointerTableOffset = profiling::ReadUint32(data, offset);
Finn Williams15db7452019-10-15 14:22:13 +010073 offset += uint32_t_size;
74
75 std::vector<uint32_t> deviceRecordOffsets(deviceRecordCount);
76 std::vector<uint32_t> counterSetOffsets(counterSetRecordCount);
77 std::vector<uint32_t> categoryOffsets(categoryRecordCount);
78
Finn Williamsd44815f2020-05-01 13:25:55 +010079 offset = deviceRecordsPointerTableOffset;
Finn Williams15db7452019-10-15 14:22:13 +010080 for (uint32_t i = 0; i < deviceRecordCount; ++i)
81 {
82 deviceRecordOffsets[i] = profiling::ReadUint32(data, offset);
83 offset += uint32_t_size;
84 }
85
Finn Williamsd44815f2020-05-01 13:25:55 +010086 offset = counterPointerTableSetOffset;
Finn Williams15db7452019-10-15 14:22:13 +010087 for (uint32_t i = 0; i < counterSetRecordCount; ++i)
88 {
89 counterSetOffsets[i] = profiling::ReadUint32(data, offset);
90 offset += uint32_t_size;
91 }
92
Finn Williamsd44815f2020-05-01 13:25:55 +010093 offset = categoriesPointerTableOffset;
Finn Williams15db7452019-10-15 14:22:13 +010094 for (uint32_t i = 0; i < categoryRecordCount; ++i)
95 {
96 categoryOffsets[i] = profiling::ReadUint32(data, offset);
97 offset += uint32_t_size;
98 }
99
Finn Williamsd44815f2020-05-01 13:25:55 +0100100 offset = deviceRecordsPointerTableOffset;
Keith Davis3201eea2019-10-24 17:30:41 +0100101 for (uint32_t deviceIndex = 0; deviceIndex < deviceRecordCount; ++deviceIndex)
Finn Williams15db7452019-10-15 14:22:13 +0100102 {
103 uint32_t deviceRecordOffset = offset + deviceRecordOffsets[deviceIndex];
104 // Device record word 0:
105 // 0:15 [16] cores: the number of individual streams of counters for one or more cores of some device
Keith Davis3201eea2019-10-24 17:30:41 +0100106 uint16_t deviceCores = profiling::ReadUint16(data, deviceRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100107 // 16:31 [16] deviceUid: the unique identifier for the device
108 deviceRecordOffset += uint16_t_size;
Keith Davis3201eea2019-10-24 17:30:41 +0100109 uint16_t deviceUid = profiling::ReadUint16(data, deviceRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100110 deviceRecordOffset += uint16_t_size;
111
112 // Device record word 1:
113 // Offset from the beginning of the device record pool to the name field.
114 uint32_t nameOffset = profiling::ReadUint32(data, deviceRecordOffset);
115
Finn Williamsd44815f2020-05-01 13:25:55 +0100116 deviceRecordOffset = deviceRecordsPointerTableOffset + nameOffset;
Finn Williams15db7452019-10-15 14:22:13 +0100117
Keith Davis3201eea2019-10-24 17:30:41 +0100118 const std::string& deviceName = GetStringNameFromBuffer(data, deviceRecordOffset);
119 const Device* registeredDevice = m_CounterDirectory.RegisterDevice(deviceName, deviceCores);
120 m_UidTranslation[registeredDevice->m_Uid] = deviceUid;
Finn Williams15db7452019-10-15 14:22:13 +0100121 }
122
Finn Williamsd44815f2020-05-01 13:25:55 +0100123 offset = counterPointerTableSetOffset;
Finn Williams15db7452019-10-15 14:22:13 +0100124 for (uint32_t counterSetIndex = 0; counterSetIndex < counterSetRecordCount; ++counterSetIndex)
125 {
126 uint32_t counterSetOffset = offset + counterSetOffsets[counterSetIndex];
127
128 // Counter set record word 0:
129 // 0:15 [16] count: the number of counters which can be active in this set at any one time
Keith Davis3201eea2019-10-24 17:30:41 +0100130 uint16_t counterSetCount = profiling::ReadUint16(data, counterSetOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100131 counterSetOffset += uint16_t_size;
132
133 // 16:31 [16] deviceUid: the unique identifier for the counter_set
Keith Davis3201eea2019-10-24 17:30:41 +0100134 uint16_t counterSetUid = profiling::ReadUint16(data, counterSetOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100135 counterSetOffset += uint16_t_size;
136
137 // Counter set record word 1:
138 // 0:31 [32] name_offset: offset from the beginning of the counter set pool to the name field
139 // The offset is always zero here, as the name field is always the first (and only) item in the pool
140 counterSetOffset += uint32_t_size;
141 counterSetOffset += uint32_t_size;
142
Keith Davis3201eea2019-10-24 17:30:41 +0100143 auto counterSet =
144 m_CounterDirectory.RegisterCounterSet(GetStringNameFromBuffer(data, counterSetOffset), counterSetCount);
145 m_UidTranslation[counterSet->m_Uid] = counterSetUid;
Finn Williams15db7452019-10-15 14:22:13 +0100146 }
Finn Williamsd44815f2020-05-01 13:25:55 +0100147 ReadCategoryRecords(data, categoriesPointerTableOffset, categoryOffsets);
Finn Williams15db7452019-10-15 14:22:13 +0100148}
149
Keith Davis3201eea2019-10-24 17:30:41 +0100150void DirectoryCaptureCommandHandler::ReadCategoryRecords(const unsigned char* const data,
151 uint32_t offset,
152 std::vector<uint32_t> categoryOffsets)
Finn Williams15db7452019-10-15 14:22:13 +0100153{
Keith Davis3201eea2019-10-24 17:30:41 +0100154 uint32_t categoryRecordCount = static_cast<uint32_t>(categoryOffsets.size());
Finn Williams15db7452019-10-15 14:22:13 +0100155
156 for (uint32_t categoryIndex = 0; categoryIndex < categoryRecordCount; ++categoryIndex)
157 {
158 uint32_t categoryRecordOffset = offset + categoryOffsets[categoryIndex];
159
Finn Williams15db7452019-10-15 14:22:13 +0100160 // Category record word 1:
161 // 0:15 Reserved, value 0x0000.
162 categoryRecordOffset += uint16_t_size;
163 // 16:31 Number of events belonging to this category.
Keith Davis3201eea2019-10-24 17:30:41 +0100164 uint32_t eventCount = profiling::ReadUint16(data, categoryRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100165 categoryRecordOffset += uint16_t_size;
166
167 // Category record word 2
168 // 0:31 Offset from the beginning of the category data pool to the event_pointer_table
169 uint32_t eventPointerTableOffset = profiling::ReadUint32(data, categoryRecordOffset);
170 categoryRecordOffset += uint32_t_size;
171
172 // Category record word 3
173 // 0:31 Offset from the beginning of the category data pool to the name field.
174 uint32_t nameOffset = profiling::ReadUint32(data, categoryRecordOffset);
175 categoryRecordOffset += uint32_t_size;
176
Finn Williams15db7452019-10-15 14:22:13 +0100177 std::vector<uint32_t> eventRecordsOffsets(eventCount);
178
Finn Williamsd44815f2020-05-01 13:25:55 +0100179 eventPointerTableOffset += offset + categoryOffsets[categoryIndex];
Finn Williams15db7452019-10-15 14:22:13 +0100180
181 for (uint32_t eventIndex = 0; eventIndex < eventCount; ++eventIndex)
182 {
183 eventRecordsOffsets[eventIndex] =
Keith Davis3201eea2019-10-24 17:30:41 +0100184 profiling::ReadUint32(data, eventPointerTableOffset + uint32_t_size * eventIndex);
Finn Williams15db7452019-10-15 14:22:13 +0100185 }
186
Keith Davis3201eea2019-10-24 17:30:41 +0100187 const std::vector<CounterDirectoryEventRecord>& eventRecords =
Finn Williamsd44815f2020-05-01 13:25:55 +0100188 ReadEventRecords(data, eventPointerTableOffset, eventRecordsOffsets);
Finn Williams15db7452019-10-15 14:22:13 +0100189
Keith Davis3201eea2019-10-24 17:30:41 +0100190 const Category* category = m_CounterDirectory.RegisterCategory(
Finn Williamsd44815f2020-05-01 13:25:55 +0100191 GetStringNameFromBuffer(data, offset + categoryOffsets[categoryIndex] + nameOffset + uint32_t_size));
Keith Davis3201eea2019-10-24 17:30:41 +0100192 for (auto& counter : eventRecords)
193 {
Keith Davise394bd92019-12-02 15:12:19 +0000194 const Counter* registeredCounter = m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
195 counter.m_CounterUid,
196 category->m_Name,
197 counter.m_CounterClass,
198 counter.m_CounterInterpolation,
199 counter.m_CounterMultiplier,
200 counter.m_CounterName,
201 counter.m_CounterDescription,
202 counter.m_CounterUnits);
Keith Davis3201eea2019-10-24 17:30:41 +0100203 m_UidTranslation[registeredCounter->m_Uid] = counter.m_CounterUid;
204 }
Finn Williams15db7452019-10-15 14:22:13 +0100205 }
Finn Williams15db7452019-10-15 14:22:13 +0100206}
207
Keith Davis3201eea2019-10-24 17:30:41 +0100208std::vector<CounterDirectoryEventRecord> DirectoryCaptureCommandHandler::ReadEventRecords(
209 const unsigned char* data, uint32_t offset, std::vector<uint32_t> eventRecordsOffsets)
Finn Williams15db7452019-10-15 14:22:13 +0100210{
211 uint32_t eventCount = static_cast<uint32_t>(eventRecordsOffsets.size());
212
Keith Davis3201eea2019-10-24 17:30:41 +0100213 std::vector<CounterDirectoryEventRecord> eventRecords(eventCount);
Finn Williams15db7452019-10-15 14:22:13 +0100214 for (unsigned long i = 0; i < eventCount; ++i)
215 {
216 uint32_t eventRecordOffset = eventRecordsOffsets[i] + offset;
217
218 // Event record word 0:
219 // 0:15 [16] count_uid: unique ID for the counter. Must be unique across all counters in all categories
220 eventRecords[i].m_CounterUid = profiling::ReadUint16(data, eventRecordOffset);
221 eventRecordOffset += uint16_t_size;
222 // 16:31 [16] max_counter_uid: if the device this event is associated with has more than one core and there
223 // is one of these counters per core this value will be set to
224 // (counter_uid + cores (from device_record)) - 1.
225 // If there is only a single core then this value will be the same as
226 // the counter_uid value
227 eventRecords[i].m_MaxCounterUid = profiling::ReadUint16(data, eventRecordOffset);
228 eventRecordOffset += uint16_t_size;
229
230 // Event record word 1:
231 // 0:15 [16] counter_set: UID of the counter_set this event is associated with. Set to zero if the event
232 // is NOT associated with a counter_set
Finn Williams78229c42020-05-08 12:24:31 +0100233 eventRecords[i].m_CounterSetUid = profiling::ReadUint16(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100234 eventRecordOffset += uint16_t_size;
235
236 // 16:31 [16] device: UID of the device this event is associated with. Set to zero if the event is NOT
237 // associated with a device
Finn Williams78229c42020-05-08 12:24:31 +0100238 eventRecords[i].m_DeviceUid = profiling::ReadUint16(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100239 eventRecordOffset += uint16_t_size;
240
241 // Event record word 2:
242 // 0:15 [16] interpolation: type describing how to interpolate each data point in a stream of data points
Finn Williams78229c42020-05-08 12:24:31 +0100243 eventRecords[i].m_CounterInterpolation = profiling::ReadUint16(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100244 eventRecordOffset += uint16_t_size;
245
246 // 16:31 [16] class: type describing how to treat each data point in a stream of data points
Finn Williams78229c42020-05-08 12:24:31 +0100247 eventRecords[i].m_CounterClass = profiling::ReadUint16(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100248 eventRecordOffset += uint16_t_size;
249
250 // Event record word 3-4:
251 // 0:63 [64] multiplier: internal data stream is represented as integer values, this allows scaling of
252 // those values as if they are fixed point numbers. Zero is not a valid value
253 uint32_t multiplier[2] = { 0u, 0u };
254
255 multiplier[0] = profiling::ReadUint32(data, eventRecordOffset);
256 eventRecordOffset += uint32_t_size;
257 multiplier[1] = profiling::ReadUint32(data, eventRecordOffset);
258 eventRecordOffset += uint32_t_size;
259
260 std::memcpy(&eventRecords[i].m_CounterMultiplier, &multiplier, sizeof(multiplier));
261
262 // Event record word 5:
263 // 0:31 [32] name_eventRecordOffset: eventRecordOffset from the
264 // beginning of the event record pool to the name field
265 // The eventRecordOffset is always zero here, as the name field is always the first item in the pool
Finn Williamsd44815f2020-05-01 13:25:55 +0100266 uint32_t nameOffset = profiling::ReadUint32(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100267 eventRecordOffset += uint32_t_size;
268
269 // Event record word 6:
270 // 0:31 [32] description_eventRecordOffset: eventRecordOffset from the
271 // beginning of the event record pool to the description field
272 // The size of the name buffer in bytes
273 uint32_t descriptionOffset = profiling::ReadUint32(data, eventRecordOffset);
274 eventRecordOffset += uint32_t_size;
275
276 // Event record word 7:
277 // 0:31 [32] units_eventRecordOffset: (optional) eventRecordOffset from the
278 // beginning of the event record pool to the units field.
279 // An eventRecordOffset value of zero indicates this field is not provided
280 uint32_t unitsOffset = profiling::ReadUint32(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100281
Finn Williamsd44815f2020-05-01 13:25:55 +0100282 eventRecords[i].m_CounterName = GetStringNameFromBuffer(data, offset +
283 eventRecordsOffsets[i] +
284 nameOffset +
285 uint32_t_size);
Finn Williams15db7452019-10-15 14:22:13 +0100286
Finn Williamsd44815f2020-05-01 13:25:55 +0100287 eventRecords[i].m_CounterDescription = GetStringNameFromBuffer(data, offset +
288 eventRecordsOffsets[i] +
289 descriptionOffset +
290 uint32_t_size);
Finn Williams15db7452019-10-15 14:22:13 +0100291
Keith Davis33ed2212020-03-30 10:43:41 +0100292 eventRecords[i].m_CounterUnits = unitsOffset == 0 ? Optional<std::string>() :
Finn Williamsd44815f2020-05-01 13:25:55 +0100293 GetStringNameFromBuffer(data, eventRecordsOffsets[i] + offset + unitsOffset + uint32_t_size);
Finn Williams15db7452019-10-15 14:22:13 +0100294 }
295
296 return eventRecords;
297}
298
299void DirectoryCaptureCommandHandler::operator()(const profiling::Packet& packet)
300{
Keith Davis3201eea2019-10-24 17:30:41 +0100301 if (!m_QuietOperation) // Are we supposed to print to stdout?
Finn Williams15db7452019-10-15 14:22:13 +0100302 {
303 std::cout << "Counter directory packet received." << std::endl;
304 }
305
Keith Davis3201eea2019-10-24 17:30:41 +0100306 // The ArmNN counter directory is static per ArmNN instance. Ensure we don't parse it a second time.
307 if (!ParsedCounterDirectory())
308 {
309 ParseData(packet);
310 m_AlreadyParsed = true;
311 }
Finn Williams15db7452019-10-15 14:22:13 +0100312
313 if (!m_QuietOperation)
314 {
Keith Davis3201eea2019-10-24 17:30:41 +0100315 armnn::profiling::PrintCounterDirectory(m_CounterDirectory);
Finn Williams15db7452019-10-15 14:22:13 +0100316 }
317}
318
Keith Davis3201eea2019-10-24 17:30:41 +0100319const ICounterDirectory& DirectoryCaptureCommandHandler::GetCounterDirectory() const
Finn Williams15db7452019-10-15 14:22:13 +0100320{
321 return m_CounterDirectory;
322}
323
Keith Davis3201eea2019-10-24 17:30:41 +0100324std::string DirectoryCaptureCommandHandler::GetStringNameFromBuffer(const unsigned char* const data, uint32_t offset)
Finn Williams15db7452019-10-15 14:22:13 +0100325{
Keith Davis3201eea2019-10-24 17:30:41 +0100326 std::string deviceName;
Rob Hughes270233f2019-11-13 11:53:48 +0000327 uint8_t nextChar = profiling::ReadUint8(data, offset);
Keith Davis3201eea2019-10-24 17:30:41 +0100328
329 while (isprint(nextChar))
330 {
331 deviceName += static_cast<char>(nextChar);
332 offset++;
333 nextChar = profiling::ReadUint8(data, offset);
334 }
335
336 return deviceName;
Finn Williams15db7452019-10-15 14:22:13 +0100337}
338
Keith Davis3201eea2019-10-24 17:30:41 +0100339} // namespace profiling
Finn Williams15db7452019-10-15 14:22:13 +0100340
Keith Davis3201eea2019-10-24 17:30:41 +0100341} // namespace armnn