blob: f2215135721f0d08c25622bd9ada04feb0bd443a [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
48 offset += uint32_t_size;
49
50 // Body header word 2:
51 // 0:15 [16] reserved: all zeros
52 offset += uint16_t_size;
53 // 16:31 [16] counter_set_count: number of entries in the counter_set_pointer_table
54 counterSetRecordCount = profiling::ReadUint16(data, offset);
55 offset += uint16_t_size;
56
57 // Body header word 3:
58 // 0:31 [32] counter_set_pointer_table_offset: offset to the counter_set_pointer_table
59 // counterPointerTableSetOffset = profiling::ReadUint32(data, offset);
60 offset += uint32_t_size;
61
62 // Body header word 4:
63 // 0:15 [16] reserved: all zeros
64 offset += uint16_t_size;
65 // 16:31 [16] categories_count: number of entries in the categories_pointer_table
66 categoryRecordCount = profiling::ReadUint16(data, offset);
67 offset += uint16_t_size;
68
69 // Body header word 5:
70 // 0:31 [32] categories_pointer_table_offset: offset to the categories_pointer_table
71 // categoriesPointerTableOffset = profiling::ReadUint32(data, offset);
72 offset += uint32_t_size;
73
74 std::vector<uint32_t> deviceRecordOffsets(deviceRecordCount);
75 std::vector<uint32_t> counterSetOffsets(counterSetRecordCount);
76 std::vector<uint32_t> categoryOffsets(categoryRecordCount);
77
78 for (uint32_t i = 0; i < deviceRecordCount; ++i)
79 {
80 deviceRecordOffsets[i] = profiling::ReadUint32(data, offset);
81 offset += uint32_t_size;
82 }
83
84 for (uint32_t i = 0; i < counterSetRecordCount; ++i)
85 {
86 counterSetOffsets[i] = profiling::ReadUint32(data, offset);
87 offset += uint32_t_size;
88 }
89
90 for (uint32_t i = 0; i < categoryRecordCount; ++i)
91 {
92 categoryOffsets[i] = profiling::ReadUint32(data, offset);
93 offset += uint32_t_size;
94 }
95
Keith Davis3201eea2019-10-24 17:30:41 +010096 for (uint32_t deviceIndex = 0; deviceIndex < deviceRecordCount; ++deviceIndex)
Finn Williams15db7452019-10-15 14:22:13 +010097 {
98 uint32_t deviceRecordOffset = offset + deviceRecordOffsets[deviceIndex];
99 // Device record word 0:
100 // 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 +0100101 uint16_t deviceCores = profiling::ReadUint16(data, deviceRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100102 // 16:31 [16] deviceUid: the unique identifier for the device
103 deviceRecordOffset += uint16_t_size;
Keith Davis3201eea2019-10-24 17:30:41 +0100104 uint16_t deviceUid = profiling::ReadUint16(data, deviceRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100105 deviceRecordOffset += uint16_t_size;
106
107 // Device record word 1:
108 // Offset from the beginning of the device record pool to the name field.
109 uint32_t nameOffset = profiling::ReadUint32(data, deviceRecordOffset);
110
111 deviceRecordOffset += uint32_t_size;
112 deviceRecordOffset += uint32_t_size;
113 deviceRecordOffset += nameOffset;
114
Keith Davis3201eea2019-10-24 17:30:41 +0100115 const std::string& deviceName = GetStringNameFromBuffer(data, deviceRecordOffset);
116 const Device* registeredDevice = m_CounterDirectory.RegisterDevice(deviceName, deviceCores);
117 m_UidTranslation[registeredDevice->m_Uid] = deviceUid;
Finn Williams15db7452019-10-15 14:22:13 +0100118 }
119
Finn Williams15db7452019-10-15 14:22:13 +0100120 for (uint32_t counterSetIndex = 0; counterSetIndex < counterSetRecordCount; ++counterSetIndex)
121 {
122 uint32_t counterSetOffset = offset + counterSetOffsets[counterSetIndex];
123
124 // Counter set record word 0:
125 // 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 +0100126 uint16_t counterSetCount = profiling::ReadUint16(data, counterSetOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100127 counterSetOffset += uint16_t_size;
128
129 // 16:31 [16] deviceUid: the unique identifier for the counter_set
Keith Davis3201eea2019-10-24 17:30:41 +0100130 uint16_t counterSetUid = profiling::ReadUint16(data, counterSetOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100131 counterSetOffset += uint16_t_size;
132
133 // Counter set record word 1:
134 // 0:31 [32] name_offset: offset from the beginning of the counter set pool to the name field
135 // The offset is always zero here, as the name field is always the first (and only) item in the pool
136 counterSetOffset += uint32_t_size;
137 counterSetOffset += uint32_t_size;
138
Keith Davis3201eea2019-10-24 17:30:41 +0100139 auto counterSet =
140 m_CounterDirectory.RegisterCounterSet(GetStringNameFromBuffer(data, counterSetOffset), counterSetCount);
141 m_UidTranslation[counterSet->m_Uid] = counterSetUid;
Finn Williams15db7452019-10-15 14:22:13 +0100142 }
Keith Davis3201eea2019-10-24 17:30:41 +0100143 ReadCategoryRecords(data, offset, categoryOffsets);
Finn Williams15db7452019-10-15 14:22:13 +0100144}
145
Keith Davis3201eea2019-10-24 17:30:41 +0100146void DirectoryCaptureCommandHandler::ReadCategoryRecords(const unsigned char* const data,
147 uint32_t offset,
148 std::vector<uint32_t> categoryOffsets)
Finn Williams15db7452019-10-15 14:22:13 +0100149{
Keith Davis3201eea2019-10-24 17:30:41 +0100150 uint32_t categoryRecordCount = static_cast<uint32_t>(categoryOffsets.size());
Finn Williams15db7452019-10-15 14:22:13 +0100151
152 for (uint32_t categoryIndex = 0; categoryIndex < categoryRecordCount; ++categoryIndex)
153 {
154 uint32_t categoryRecordOffset = offset + categoryOffsets[categoryIndex];
155
156 // Category record word 0:
157 // 0:15 The deviceUid of a counter_set the category is associated with.
158 // Set to zero if the category is NOT associated with a counter set.
Keith Davis3201eea2019-10-24 17:30:41 +0100159 uint16_t counterSetUid = profiling::ReadUint16(data, categoryRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100160 categoryRecordOffset += uint16_t_size;
161
162 // 16:31 The deviceUid of a device element which identifies some hardware device that the category belongs to.
163 // Set to zero if the category is NOT associated with a device
Keith Davis3201eea2019-10-24 17:30:41 +0100164 uint16_t deviceUid = profiling::ReadUint16(data, categoryRecordOffset);
165
Finn Williams15db7452019-10-15 14:22:13 +0100166 categoryRecordOffset += uint16_t_size;
167
168 // Category record word 1:
169 // 0:15 Reserved, value 0x0000.
170 categoryRecordOffset += uint16_t_size;
171 // 16:31 Number of events belonging to this category.
Keith Davis3201eea2019-10-24 17:30:41 +0100172 uint32_t eventCount = profiling::ReadUint16(data, categoryRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100173 categoryRecordOffset += uint16_t_size;
174
175 // Category record word 2
176 // 0:31 Offset from the beginning of the category data pool to the event_pointer_table
177 uint32_t eventPointerTableOffset = profiling::ReadUint32(data, categoryRecordOffset);
178 categoryRecordOffset += uint32_t_size;
179
180 // Category record word 3
181 // 0:31 Offset from the beginning of the category data pool to the name field.
182 uint32_t nameOffset = profiling::ReadUint32(data, categoryRecordOffset);
183 categoryRecordOffset += uint32_t_size;
184
Finn Williams15db7452019-10-15 14:22:13 +0100185 std::vector<uint32_t> eventRecordsOffsets(eventCount);
186
187 eventPointerTableOffset += categoryRecordOffset;
188
189 for (uint32_t eventIndex = 0; eventIndex < eventCount; ++eventIndex)
190 {
191 eventRecordsOffsets[eventIndex] =
Keith Davis3201eea2019-10-24 17:30:41 +0100192 profiling::ReadUint32(data, eventPointerTableOffset + uint32_t_size * eventIndex);
Finn Williams15db7452019-10-15 14:22:13 +0100193 }
194
Keith Davis3201eea2019-10-24 17:30:41 +0100195 const std::vector<CounterDirectoryEventRecord>& eventRecords =
196 ReadEventRecords(data, categoryRecordOffset, eventRecordsOffsets);
Finn Williams15db7452019-10-15 14:22:13 +0100197 categoryRecordOffset += uint32_t_size;
198
Keith Davis3201eea2019-10-24 17:30:41 +0100199 const Category* category = m_CounterDirectory.RegisterCategory(
200 GetStringNameFromBuffer(data, categoryRecordOffset + nameOffset), deviceUid, counterSetUid);
201 for (auto& counter : eventRecords)
202 {
Keith Davise394bd92019-12-02 15:12:19 +0000203 const Counter* registeredCounter = m_CounterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
204 counter.m_CounterUid,
205 category->m_Name,
206 counter.m_CounterClass,
207 counter.m_CounterInterpolation,
208 counter.m_CounterMultiplier,
209 counter.m_CounterName,
210 counter.m_CounterDescription,
211 counter.m_CounterUnits);
Keith Davis3201eea2019-10-24 17:30:41 +0100212 m_UidTranslation[registeredCounter->m_Uid] = counter.m_CounterUid;
213 }
Finn Williams15db7452019-10-15 14:22:13 +0100214 }
Finn Williams15db7452019-10-15 14:22:13 +0100215}
216
Keith Davis3201eea2019-10-24 17:30:41 +0100217std::vector<CounterDirectoryEventRecord> DirectoryCaptureCommandHandler::ReadEventRecords(
218 const unsigned char* data, uint32_t offset, std::vector<uint32_t> eventRecordsOffsets)
Finn Williams15db7452019-10-15 14:22:13 +0100219{
220 uint32_t eventCount = static_cast<uint32_t>(eventRecordsOffsets.size());
221
Keith Davis3201eea2019-10-24 17:30:41 +0100222 std::vector<CounterDirectoryEventRecord> eventRecords(eventCount);
Finn Williams15db7452019-10-15 14:22:13 +0100223 for (unsigned long i = 0; i < eventCount; ++i)
224 {
225 uint32_t eventRecordOffset = eventRecordsOffsets[i] + offset;
226
227 // Event record word 0:
228 // 0:15 [16] count_uid: unique ID for the counter. Must be unique across all counters in all categories
229 eventRecords[i].m_CounterUid = profiling::ReadUint16(data, eventRecordOffset);
230 eventRecordOffset += uint16_t_size;
231 // 16:31 [16] max_counter_uid: if the device this event is associated with has more than one core and there
232 // is one of these counters per core this value will be set to
233 // (counter_uid + cores (from device_record)) - 1.
234 // If there is only a single core then this value will be the same as
235 // the counter_uid value
236 eventRecords[i].m_MaxCounterUid = profiling::ReadUint16(data, eventRecordOffset);
237 eventRecordOffset += uint16_t_size;
238
239 // Event record word 1:
240 // 0:15 [16] counter_set: UID of the counter_set this event is associated with. Set to zero if the event
241 // is NOT associated with a counter_set
242 eventRecords[i].m_DeviceUid = profiling::ReadUint16(data, eventRecordOffset);
243 eventRecordOffset += uint16_t_size;
244
245 // 16:31 [16] device: UID of the device this event is associated with. Set to zero if the event is NOT
246 // associated with a device
247 eventRecords[i].m_CounterSetUid = profiling::ReadUint16(data, eventRecordOffset);
248 eventRecordOffset += uint16_t_size;
249
250 // Event record word 2:
251 // 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 +0100252 eventRecords[i].m_CounterClass = profiling::ReadUint16(data, eventRecordOffset);
Finn Williams15db7452019-10-15 14:22:13 +0100253 eventRecordOffset += uint16_t_size;
254
255 // 16:31 [16] class: type describing how to treat each data point in a stream of data points
256 eventRecords[i].m_CounterInterpolation = profiling::ReadUint16(data, eventRecordOffset);
257 eventRecordOffset += uint16_t_size;
258
259 // Event record word 3-4:
260 // 0:63 [64] multiplier: internal data stream is represented as integer values, this allows scaling of
261 // those values as if they are fixed point numbers. Zero is not a valid value
262 uint32_t multiplier[2] = { 0u, 0u };
263
264 multiplier[0] = profiling::ReadUint32(data, eventRecordOffset);
265 eventRecordOffset += uint32_t_size;
266 multiplier[1] = profiling::ReadUint32(data, eventRecordOffset);
267 eventRecordOffset += uint32_t_size;
268
269 std::memcpy(&eventRecords[i].m_CounterMultiplier, &multiplier, sizeof(multiplier));
270
271 // Event record word 5:
272 // 0:31 [32] name_eventRecordOffset: eventRecordOffset from the
273 // beginning of the event record pool to the name field
274 // The eventRecordOffset is always zero here, as the name field is always the first item in the pool
275 eventRecordOffset += uint32_t_size;
276
277 // Event record word 6:
278 // 0:31 [32] description_eventRecordOffset: eventRecordOffset from the
279 // beginning of the event record pool to the description field
280 // The size of the name buffer in bytes
281 uint32_t descriptionOffset = profiling::ReadUint32(data, eventRecordOffset);
282 eventRecordOffset += uint32_t_size;
283
284 // Event record word 7:
285 // 0:31 [32] units_eventRecordOffset: (optional) eventRecordOffset from the
286 // beginning of the event record pool to the units field.
287 // An eventRecordOffset value of zero indicates this field is not provided
288 uint32_t unitsOffset = profiling::ReadUint32(data, eventRecordOffset);
289 eventRecordOffset += uint32_t_size;
290 eventRecordOffset += uint32_t_size;
291
292 eventRecords[i].m_CounterName = GetStringNameFromBuffer(data, eventRecordOffset);
293
294 eventRecords[i].m_CounterDescription = GetStringNameFromBuffer(data, eventRecordOffset + descriptionOffset);
295
296 eventRecords[i].m_CounterUnits = GetStringNameFromBuffer(data, eventRecordOffset + unitsOffset);
297 }
298
299 return eventRecords;
300}
301
302void DirectoryCaptureCommandHandler::operator()(const profiling::Packet& packet)
303{
Keith Davis3201eea2019-10-24 17:30:41 +0100304 if (!m_QuietOperation) // Are we supposed to print to stdout?
Finn Williams15db7452019-10-15 14:22:13 +0100305 {
306 std::cout << "Counter directory packet received." << std::endl;
307 }
308
Keith Davis3201eea2019-10-24 17:30:41 +0100309 // The ArmNN counter directory is static per ArmNN instance. Ensure we don't parse it a second time.
310 if (!ParsedCounterDirectory())
311 {
312 ParseData(packet);
313 m_AlreadyParsed = true;
314 }
Finn Williams15db7452019-10-15 14:22:13 +0100315
316 if (!m_QuietOperation)
317 {
Keith Davis3201eea2019-10-24 17:30:41 +0100318 armnn::profiling::PrintCounterDirectory(m_CounterDirectory);
Finn Williams15db7452019-10-15 14:22:13 +0100319 }
320}
321
Keith Davis3201eea2019-10-24 17:30:41 +0100322const ICounterDirectory& DirectoryCaptureCommandHandler::GetCounterDirectory() const
Finn Williams15db7452019-10-15 14:22:13 +0100323{
324 return m_CounterDirectory;
325}
326
Keith Davis3201eea2019-10-24 17:30:41 +0100327std::string DirectoryCaptureCommandHandler::GetStringNameFromBuffer(const unsigned char* const data, uint32_t offset)
Finn Williams15db7452019-10-15 14:22:13 +0100328{
Keith Davis3201eea2019-10-24 17:30:41 +0100329 std::string deviceName;
Rob Hughes270233f2019-11-13 11:53:48 +0000330 uint8_t nextChar = profiling::ReadUint8(data, offset);
Keith Davis3201eea2019-10-24 17:30:41 +0100331
332 while (isprint(nextChar))
333 {
334 deviceName += static_cast<char>(nextChar);
335 offset++;
336 nextChar = profiling::ReadUint8(data, offset);
337 }
338
339 return deviceName;
Finn Williams15db7452019-10-15 14:22:13 +0100340}
341
Keith Davis3201eea2019-10-24 17:30:41 +0100342} // namespace profiling
Finn Williams15db7452019-10-15 14:22:13 +0100343
Keith Davis3201eea2019-10-24 17:30:41 +0100344} // namespace armnn