blob: 65a7880d507e795ddc8692654de317c817641fc9 [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//
5
Finn Williamse63a0262019-10-22 10:30:49 +01006#include <atomic>
Finn Williams15db7452019-10-15 14:22:13 +01007#include "DirectoryCaptureCommandHandler.hpp"
Keith Davis3201eea2019-10-24 17:30:41 +01008#include "SendCounterPacket.hpp"
9
10#include <iostream>
Finn Williams15db7452019-10-15 14:22:13 +010011
12namespace armnn
13{
14
Keith Davis3201eea2019-10-24 17:30:41 +010015namespace profiling
Finn Williams15db7452019-10-15 14:22:13 +010016{
17
18// Utils
19uint32_t uint16_t_size = sizeof(uint16_t);
20uint32_t uint32_t_size = sizeof(uint32_t);
21
22void DirectoryCaptureCommandHandler::ParseData(const armnn::profiling::Packet& packet)
23{
24 uint16_t categoryRecordCount;
25 uint16_t counterSetRecordCount;
26 uint16_t deviceRecordCount;
27
28 uint32_t offset = 0;
29
30 if (packet.GetLength() < 8)
31 {
32 std::cout << "Counter directory packet received." << std::endl;
33 return;
34 }
35
Keith Davis3201eea2019-10-24 17:30:41 +010036 const unsigned char* data = packet.GetData();
Finn Williams15db7452019-10-15 14:22:13 +010037 // Body header word 0:
38 // 0:15 [16] reserved: all zeros
39 offset += uint16_t_size;
40 // 16:31 [16] device_records_count: number of entries in the device_records_pointer_table
41 deviceRecordCount = profiling::ReadUint16(data, offset);
42 offset += uint16_t_size;
43
44 // Body header word 1:
45 // 0:31 [32] device_records_pointer_table_offset: offset to the device_records_pointer_table
46 // The offset is always zero here, as the device record pointer table field is always the first item in the pool
47 offset += uint32_t_size;
48
49 // Body header word 2:
50 // 0:15 [16] reserved: all zeros
51 offset += uint16_t_size;
52 // 16:31 [16] counter_set_count: number of entries in the counter_set_pointer_table
53 counterSetRecordCount = profiling::ReadUint16(data, offset);
54 offset += uint16_t_size;
55
56 // Body header word 3:
57 // 0:31 [32] counter_set_pointer_table_offset: offset to the counter_set_pointer_table
58 // counterPointerTableSetOffset = profiling::ReadUint32(data, offset);
59 offset += uint32_t_size;
60
61 // Body header word 4:
62 // 0:15 [16] reserved: all zeros
63 offset += uint16_t_size;
64 // 16:31 [16] categories_count: number of entries in the categories_pointer_table
65 categoryRecordCount = profiling::ReadUint16(data, offset);
66 offset += uint16_t_size;
67
68 // Body header word 5:
69 // 0:31 [32] categories_pointer_table_offset: offset to the categories_pointer_table
70 // categoriesPointerTableOffset = profiling::ReadUint32(data, offset);
71 offset += uint32_t_size;
72
73 std::vector<uint32_t> deviceRecordOffsets(deviceRecordCount);
74 std::vector<uint32_t> counterSetOffsets(counterSetRecordCount);
75 std::vector<uint32_t> categoryOffsets(categoryRecordCount);
76
77 for (uint32_t i = 0; i < deviceRecordCount; ++i)
78 {
79 deviceRecordOffsets[i] = profiling::ReadUint32(data, offset);
80 offset += uint32_t_size;
81 }
82
83 for (uint32_t i = 0; i < counterSetRecordCount; ++i)
84 {
85 counterSetOffsets[i] = profiling::ReadUint32(data, offset);
86 offset += uint32_t_size;
87 }
88
89 for (uint32_t i = 0; i < categoryRecordCount; ++i)
90 {
91 categoryOffsets[i] = profiling::ReadUint32(data, offset);
92 offset += uint32_t_size;
93 }
94
Keith Davis3201eea2019-10-24 17:30:41 +010095 for (uint32_t deviceIndex = 0; deviceIndex < deviceRecordCount; ++deviceIndex)
Finn Williams15db7452019-10-15 14:22:13 +010096 {
97 uint32_t deviceRecordOffset = offset + deviceRecordOffsets[deviceIndex];
98 // Device record word 0:
99 // 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 +0100100 uint16_t deviceCores = profiling::ReadUint16(data, deviceRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100101 // 16:31 [16] deviceUid: the unique identifier for the device
102 deviceRecordOffset += uint16_t_size;
Keith Davis3201eea2019-10-24 17:30:41 +0100103 uint16_t deviceUid = profiling::ReadUint16(data, deviceRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100104 deviceRecordOffset += uint16_t_size;
105
106 // Device record word 1:
107 // Offset from the beginning of the device record pool to the name field.
108 uint32_t nameOffset = profiling::ReadUint32(data, deviceRecordOffset);
109
110 deviceRecordOffset += uint32_t_size;
111 deviceRecordOffset += uint32_t_size;
112 deviceRecordOffset += nameOffset;
113
Keith Davis3201eea2019-10-24 17:30:41 +0100114 const std::string& deviceName = GetStringNameFromBuffer(data, deviceRecordOffset);
115 const Device* registeredDevice = m_CounterDirectory.RegisterDevice(deviceName, deviceCores);
116 m_UidTranslation[registeredDevice->m_Uid] = deviceUid;
Finn Williams15db7452019-10-15 14:22:13 +0100117 }
118
Finn Williams15db7452019-10-15 14:22:13 +0100119 for (uint32_t counterSetIndex = 0; counterSetIndex < counterSetRecordCount; ++counterSetIndex)
120 {
121 uint32_t counterSetOffset = offset + counterSetOffsets[counterSetIndex];
122
123 // Counter set record word 0:
124 // 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 +0100125 uint16_t counterSetCount = profiling::ReadUint16(data, counterSetOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100126 counterSetOffset += uint16_t_size;
127
128 // 16:31 [16] deviceUid: the unique identifier for the counter_set
Keith Davis3201eea2019-10-24 17:30:41 +0100129 uint16_t counterSetUid = profiling::ReadUint16(data, counterSetOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100130 counterSetOffset += uint16_t_size;
131
132 // Counter set record word 1:
133 // 0:31 [32] name_offset: offset from the beginning of the counter set pool to the name field
134 // The offset is always zero here, as the name field is always the first (and only) item in the pool
135 counterSetOffset += uint32_t_size;
136 counterSetOffset += uint32_t_size;
137
Keith Davis3201eea2019-10-24 17:30:41 +0100138 auto counterSet =
139 m_CounterDirectory.RegisterCounterSet(GetStringNameFromBuffer(data, counterSetOffset), counterSetCount);
140 m_UidTranslation[counterSet->m_Uid] = counterSetUid;
Finn Williams15db7452019-10-15 14:22:13 +0100141 }
Keith Davis3201eea2019-10-24 17:30:41 +0100142 ReadCategoryRecords(data, offset, categoryOffsets);
Finn Williams15db7452019-10-15 14:22:13 +0100143}
144
Keith Davis3201eea2019-10-24 17:30:41 +0100145void DirectoryCaptureCommandHandler::ReadCategoryRecords(const unsigned char* const data,
146 uint32_t offset,
147 std::vector<uint32_t> categoryOffsets)
Finn Williams15db7452019-10-15 14:22:13 +0100148{
Keith Davis3201eea2019-10-24 17:30:41 +0100149 uint32_t categoryRecordCount = static_cast<uint32_t>(categoryOffsets.size());
Finn Williams15db7452019-10-15 14:22:13 +0100150
151 for (uint32_t categoryIndex = 0; categoryIndex < categoryRecordCount; ++categoryIndex)
152 {
153 uint32_t categoryRecordOffset = offset + categoryOffsets[categoryIndex];
154
155 // Category record word 0:
156 // 0:15 The deviceUid of a counter_set the category is associated with.
157 // Set to zero if the category is NOT associated with a counter set.
Keith Davis3201eea2019-10-24 17:30:41 +0100158 uint16_t counterSetUid = profiling::ReadUint16(data, categoryRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100159 categoryRecordOffset += uint16_t_size;
160
161 // 16:31 The deviceUid of a device element which identifies some hardware device that the category belongs to.
162 // Set to zero if the category is NOT associated with a device
Keith Davis3201eea2019-10-24 17:30:41 +0100163 uint16_t deviceUid = profiling::ReadUint16(data, categoryRecordOffset);
164
Finn Williams15db7452019-10-15 14:22:13 +0100165 categoryRecordOffset += uint16_t_size;
166
167 // Category record word 1:
168 // 0:15 Reserved, value 0x0000.
169 categoryRecordOffset += uint16_t_size;
170 // 16:31 Number of events belonging to this category.
Keith Davis3201eea2019-10-24 17:30:41 +0100171 uint32_t eventCount = profiling::ReadUint16(data, categoryRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100172 categoryRecordOffset += uint16_t_size;
173
174 // Category record word 2
175 // 0:31 Offset from the beginning of the category data pool to the event_pointer_table
176 uint32_t eventPointerTableOffset = profiling::ReadUint32(data, categoryRecordOffset);
177 categoryRecordOffset += uint32_t_size;
178
179 // Category record word 3
180 // 0:31 Offset from the beginning of the category data pool to the name field.
181 uint32_t nameOffset = profiling::ReadUint32(data, categoryRecordOffset);
182 categoryRecordOffset += uint32_t_size;
183
Finn Williams15db7452019-10-15 14:22:13 +0100184 std::vector<uint32_t> eventRecordsOffsets(eventCount);
185
186 eventPointerTableOffset += categoryRecordOffset;
187
188 for (uint32_t eventIndex = 0; eventIndex < eventCount; ++eventIndex)
189 {
190 eventRecordsOffsets[eventIndex] =
Keith Davis3201eea2019-10-24 17:30:41 +0100191 profiling::ReadUint32(data, eventPointerTableOffset + uint32_t_size * eventIndex);
Finn Williams15db7452019-10-15 14:22:13 +0100192 }
193
Keith Davis3201eea2019-10-24 17:30:41 +0100194 const std::vector<CounterDirectoryEventRecord>& eventRecords =
195 ReadEventRecords(data, categoryRecordOffset, eventRecordsOffsets);
Finn Williams15db7452019-10-15 14:22:13 +0100196 categoryRecordOffset += uint32_t_size;
197
Keith Davis3201eea2019-10-24 17:30:41 +0100198 const Category* category = m_CounterDirectory.RegisterCategory(
199 GetStringNameFromBuffer(data, categoryRecordOffset + nameOffset), deviceUid, counterSetUid);
200 for (auto& counter : eventRecords)
201 {
202 const Counter* registeredCounter = m_CounterDirectory.RegisterCounter(
203 category->m_Name, counter.m_CounterClass, counter.m_CounterInterpolation, counter.m_CounterMultiplier,
204 counter.m_CounterName, counter.m_CounterDescription, counter.m_CounterUnits);
205 m_UidTranslation[registeredCounter->m_Uid] = counter.m_CounterUid;
206 }
Finn Williams15db7452019-10-15 14:22:13 +0100207 }
Finn Williams15db7452019-10-15 14:22:13 +0100208}
209
Keith Davis3201eea2019-10-24 17:30:41 +0100210std::vector<CounterDirectoryEventRecord> DirectoryCaptureCommandHandler::ReadEventRecords(
211 const unsigned char* data, uint32_t offset, std::vector<uint32_t> eventRecordsOffsets)
Finn Williams15db7452019-10-15 14:22:13 +0100212{
213 uint32_t eventCount = static_cast<uint32_t>(eventRecordsOffsets.size());
214
Keith Davis3201eea2019-10-24 17:30:41 +0100215 std::vector<CounterDirectoryEventRecord> eventRecords(eventCount);
Finn Williams15db7452019-10-15 14:22:13 +0100216 for (unsigned long i = 0; i < eventCount; ++i)
217 {
218 uint32_t eventRecordOffset = eventRecordsOffsets[i] + offset;
219
220 // Event record word 0:
221 // 0:15 [16] count_uid: unique ID for the counter. Must be unique across all counters in all categories
222 eventRecords[i].m_CounterUid = profiling::ReadUint16(data, eventRecordOffset);
223 eventRecordOffset += uint16_t_size;
224 // 16:31 [16] max_counter_uid: if the device this event is associated with has more than one core and there
225 // is one of these counters per core this value will be set to
226 // (counter_uid + cores (from device_record)) - 1.
227 // If there is only a single core then this value will be the same as
228 // the counter_uid value
229 eventRecords[i].m_MaxCounterUid = profiling::ReadUint16(data, eventRecordOffset);
230 eventRecordOffset += uint16_t_size;
231
232 // Event record word 1:
233 // 0:15 [16] counter_set: UID of the counter_set this event is associated with. Set to zero if the event
234 // is NOT associated with a counter_set
235 eventRecords[i].m_DeviceUid = profiling::ReadUint16(data, eventRecordOffset);
236 eventRecordOffset += uint16_t_size;
237
238 // 16:31 [16] device: UID of the device this event is associated with. Set to zero if the event is NOT
239 // associated with a device
240 eventRecords[i].m_CounterSetUid = profiling::ReadUint16(data, eventRecordOffset);
241 eventRecordOffset += uint16_t_size;
242
243 // Event record word 2:
244 // 0:15 [16] interpolation: type describing how to interpolate each data point in a stream of data points
Keith Davis3201eea2019-10-24 17:30:41 +0100245 eventRecords[i].m_CounterClass = profiling::ReadUint16(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100246 eventRecordOffset += uint16_t_size;
247
248 // 16:31 [16] class: type describing how to treat each data point in a stream of data points
249 eventRecords[i].m_CounterInterpolation = profiling::ReadUint16(data, eventRecordOffset);
250 eventRecordOffset += uint16_t_size;
251
252 // Event record word 3-4:
253 // 0:63 [64] multiplier: internal data stream is represented as integer values, this allows scaling of
254 // those values as if they are fixed point numbers. Zero is not a valid value
255 uint32_t multiplier[2] = { 0u, 0u };
256
257 multiplier[0] = profiling::ReadUint32(data, eventRecordOffset);
258 eventRecordOffset += uint32_t_size;
259 multiplier[1] = profiling::ReadUint32(data, eventRecordOffset);
260 eventRecordOffset += uint32_t_size;
261
262 std::memcpy(&eventRecords[i].m_CounterMultiplier, &multiplier, sizeof(multiplier));
263
264 // Event record word 5:
265 // 0:31 [32] name_eventRecordOffset: eventRecordOffset from the
266 // beginning of the event record pool to the name field
267 // The eventRecordOffset is always zero here, as the name field is always the first item in the pool
268 eventRecordOffset += uint32_t_size;
269
270 // Event record word 6:
271 // 0:31 [32] description_eventRecordOffset: eventRecordOffset from the
272 // beginning of the event record pool to the description field
273 // The size of the name buffer in bytes
274 uint32_t descriptionOffset = profiling::ReadUint32(data, eventRecordOffset);
275 eventRecordOffset += uint32_t_size;
276
277 // Event record word 7:
278 // 0:31 [32] units_eventRecordOffset: (optional) eventRecordOffset from the
279 // beginning of the event record pool to the units field.
280 // An eventRecordOffset value of zero indicates this field is not provided
281 uint32_t unitsOffset = profiling::ReadUint32(data, eventRecordOffset);
282 eventRecordOffset += uint32_t_size;
283 eventRecordOffset += uint32_t_size;
284
285 eventRecords[i].m_CounterName = GetStringNameFromBuffer(data, eventRecordOffset);
286
287 eventRecords[i].m_CounterDescription = GetStringNameFromBuffer(data, eventRecordOffset + descriptionOffset);
288
289 eventRecords[i].m_CounterUnits = GetStringNameFromBuffer(data, eventRecordOffset + unitsOffset);
290 }
291
292 return eventRecords;
293}
294
295void DirectoryCaptureCommandHandler::operator()(const profiling::Packet& packet)
296{
Keith Davis3201eea2019-10-24 17:30:41 +0100297 if (!m_QuietOperation) // Are we supposed to print to stdout?
Finn Williams15db7452019-10-15 14:22:13 +0100298 {
299 std::cout << "Counter directory packet received." << std::endl;
300 }
301
Keith Davis3201eea2019-10-24 17:30:41 +0100302 // The ArmNN counter directory is static per ArmNN instance. Ensure we don't parse it a second time.
303 if (!ParsedCounterDirectory())
304 {
305 ParseData(packet);
306 m_AlreadyParsed = true;
307 }
Finn Williams15db7452019-10-15 14:22:13 +0100308
309 if (!m_QuietOperation)
310 {
Keith Davis3201eea2019-10-24 17:30:41 +0100311 armnn::profiling::PrintCounterDirectory(m_CounterDirectory);
Finn Williams15db7452019-10-15 14:22:13 +0100312 }
313}
314
Keith Davis3201eea2019-10-24 17:30:41 +0100315const ICounterDirectory& DirectoryCaptureCommandHandler::GetCounterDirectory() const
Finn Williams15db7452019-10-15 14:22:13 +0100316{
317 return m_CounterDirectory;
318}
319
Keith Davis3201eea2019-10-24 17:30:41 +0100320std::string DirectoryCaptureCommandHandler::GetStringNameFromBuffer(const unsigned char* const data, uint32_t offset)
Finn Williams15db7452019-10-15 14:22:13 +0100321{
Keith Davis3201eea2019-10-24 17:30:41 +0100322 std::string deviceName;
Rob Hughes270233f2019-11-13 11:53:48 +0000323 uint8_t nextChar = profiling::ReadUint8(data, offset);
Keith Davis3201eea2019-10-24 17:30:41 +0100324
325 while (isprint(nextChar))
326 {
327 deviceName += static_cast<char>(nextChar);
328 offset++;
329 nextChar = profiling::ReadUint8(data, offset);
330 }
331
332 return deviceName;
Finn Williams15db7452019-10-15 14:22:13 +0100333}
334
Keith Davis3201eea2019-10-24 17:30:41 +0100335} // namespace profiling
Finn Williams15db7452019-10-15 14:22:13 +0100336
Keith Davis3201eea2019-10-24 17:30:41 +0100337} // namespace armnn