blob: eafef0b53c00bb937e46a12b14e6b5fa5881c96d [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
6#include <atomic>
7#include "DirectoryCaptureCommandHandler.hpp"
8
9namespace armnn
10{
11
12namespace gatordmock
13{
14
15// Utils
16uint32_t uint16_t_size = sizeof(uint16_t);
17uint32_t uint32_t_size = sizeof(uint32_t);
18
19void DirectoryCaptureCommandHandler::ParseData(const armnn::profiling::Packet& packet)
20{
21 uint16_t categoryRecordCount;
22 uint16_t counterSetRecordCount;
23 uint16_t deviceRecordCount;
24
25 uint32_t offset = 0;
26
27 if (packet.GetLength() < 8)
28 {
29 std::cout << "Counter directory packet received." << std::endl;
30 return;
31 }
32
33 const unsigned char* data = reinterpret_cast<const unsigned char*>(packet.GetData());
34 // Body header word 0:
35 // 0:15 [16] reserved: all zeros
36 offset += uint16_t_size;
37 // 16:31 [16] device_records_count: number of entries in the device_records_pointer_table
38 deviceRecordCount = profiling::ReadUint16(data, offset);
39 offset += uint16_t_size;
40
41 // Body header word 1:
42 // 0:31 [32] device_records_pointer_table_offset: offset to the device_records_pointer_table
43 // The offset is always zero here, as the device record pointer table field is always the first item in the pool
44 offset += uint32_t_size;
45
46 // Body header word 2:
47 // 0:15 [16] reserved: all zeros
48 offset += uint16_t_size;
49 // 16:31 [16] counter_set_count: number of entries in the counter_set_pointer_table
50 counterSetRecordCount = profiling::ReadUint16(data, offset);
51 offset += uint16_t_size;
52
53 // Body header word 3:
54 // 0:31 [32] counter_set_pointer_table_offset: offset to the counter_set_pointer_table
55 // counterPointerTableSetOffset = profiling::ReadUint32(data, offset);
56 offset += uint32_t_size;
57
58 // Body header word 4:
59 // 0:15 [16] reserved: all zeros
60 offset += uint16_t_size;
61 // 16:31 [16] categories_count: number of entries in the categories_pointer_table
62 categoryRecordCount = profiling::ReadUint16(data, offset);
63 offset += uint16_t_size;
64
65 // Body header word 5:
66 // 0:31 [32] categories_pointer_table_offset: offset to the categories_pointer_table
67 // categoriesPointerTableOffset = profiling::ReadUint32(data, offset);
68 offset += uint32_t_size;
69
70 std::vector<uint32_t> deviceRecordOffsets(deviceRecordCount);
71 std::vector<uint32_t> counterSetOffsets(counterSetRecordCount);
72 std::vector<uint32_t> categoryOffsets(categoryRecordCount);
73
74 for (uint32_t i = 0; i < deviceRecordCount; ++i)
75 {
76 deviceRecordOffsets[i] = profiling::ReadUint32(data, offset);
77 offset += uint32_t_size;
78 }
79
80 for (uint32_t i = 0; i < counterSetRecordCount; ++i)
81 {
82 counterSetOffsets[i] = profiling::ReadUint32(data, offset);
83 offset += uint32_t_size;
84 }
85
86 for (uint32_t i = 0; i < categoryRecordCount; ++i)
87 {
88 categoryOffsets[i] = profiling::ReadUint32(data, offset);
89 offset += uint32_t_size;
90 }
91
92 m_CounterDirectory.m_DeviceRecords = ReadDeviceRecords(data, offset, deviceRecordOffsets);
93 m_CounterDirectory.m_CounterSets = ReadCounterSetRecords(data, offset, counterSetOffsets);
94 m_CounterDirectory.m_Categories = ReadCategoryRecords(data, offset, categoryOffsets);
95
96 m_CounterDirectoryCount.operator++(std::memory_order_release);
97}
98
99std::vector<DeviceRecord> DirectoryCaptureCommandHandler::ReadDeviceRecords(const unsigned char* const data,
100 uint32_t offset,
101 std::vector<uint32_t> deviceRecordOffsets)
102{
103 uint32_t deviceRecordCount = static_cast<uint32_t >(deviceRecordOffsets.size());
104 std::vector<DeviceRecord> deviceRecords(deviceRecordCount);
105
106 for(uint32_t deviceIndex = 0; deviceIndex < deviceRecordCount; ++deviceIndex)
107 {
108 uint32_t deviceRecordOffset = offset + deviceRecordOffsets[deviceIndex];
109 // Device record word 0:
110 // 0:15 [16] cores: the number of individual streams of counters for one or more cores of some device
111 deviceRecords[deviceIndex].m_DeviceCores = profiling::ReadUint16(data, deviceRecordOffset);
112 // 16:31 [16] deviceUid: the unique identifier for the device
113 deviceRecordOffset += uint16_t_size;
114 deviceRecords[deviceIndex].m_DeviceUid = profiling::ReadUint16(data, deviceRecordOffset);
115 deviceRecordOffset += uint16_t_size;
116
117 // Device record word 1:
118 // Offset from the beginning of the device record pool to the name field.
119 uint32_t nameOffset = profiling::ReadUint32(data, deviceRecordOffset);
120
121 deviceRecordOffset += uint32_t_size;
122 deviceRecordOffset += uint32_t_size;
123 deviceRecordOffset += nameOffset;
124
125 deviceRecords[deviceIndex].m_DeviceName = GetStringNameFromBuffer(data, deviceRecordOffset);
126 }
127
128 return deviceRecords;
129}
130
131
132std::vector<CounterSetRecord>
133 DirectoryCaptureCommandHandler::ReadCounterSetRecords(const unsigned char* const data,
134 uint32_t offset,
135 std::vector<uint32_t> counterSetOffsets)
136{
137 uint32_t counterSetRecordCount = static_cast<uint32_t >(counterSetOffsets.size());
138 std::vector<CounterSetRecord> counterSets(counterSetRecordCount);
139
140 for (uint32_t counterSetIndex = 0; counterSetIndex < counterSetRecordCount; ++counterSetIndex)
141 {
142 uint32_t counterSetOffset = offset + counterSetOffsets[counterSetIndex];
143
144 // Counter set record word 0:
145 // 0:15 [16] count: the number of counters which can be active in this set at any one time
146 counterSets[counterSetIndex].m_CounterSetCount = profiling::ReadUint16(data, counterSetOffset);
147 counterSetOffset += uint16_t_size;
148
149 // 16:31 [16] deviceUid: the unique identifier for the counter_set
150 counterSets[counterSetIndex].m_CounterSetUid = profiling::ReadUint16(data, counterSetOffset);
151 counterSetOffset += uint16_t_size;
152
153 // Counter set record word 1:
154 // 0:31 [32] name_offset: offset from the beginning of the counter set pool to the name field
155 // The offset is always zero here, as the name field is always the first (and only) item in the pool
156 counterSetOffset += uint32_t_size;
157 counterSetOffset += uint32_t_size;
158
159 counterSets[counterSetIndex].m_CounterSetName = GetStringNameFromBuffer(data, counterSetOffset);
160 }
161
162 return counterSets;
163}
164
165std::vector<CategoryRecord> DirectoryCaptureCommandHandler::ReadCategoryRecords(const unsigned char* const data,
166 uint32_t offset,
167 std::vector<uint32_t> categoryOffsets)
168{
169 uint32_t categoryRecordCount = static_cast<uint32_t >(categoryOffsets.size());
170 std::vector<CategoryRecord> categories(categoryRecordCount);
171
172 for (uint32_t categoryIndex = 0; categoryIndex < categoryRecordCount; ++categoryIndex)
173 {
174 uint32_t categoryRecordOffset = offset + categoryOffsets[categoryIndex];
175
176 // Category record word 0:
177 // 0:15 The deviceUid of a counter_set the category is associated with.
178 // Set to zero if the category is NOT associated with a counter set.
179 categories[categoryIndex].m_CounterSet = profiling::ReadUint16(data, categoryRecordOffset);
180 categoryRecordOffset += uint16_t_size;
181
182 // 16:31 The deviceUid of a device element which identifies some hardware device that the category belongs to.
183 // Set to zero if the category is NOT associated with a device
184 categories[categoryIndex].m_DeviceUid = profiling::ReadUint16(data, categoryRecordOffset);
185 categoryRecordOffset += uint16_t_size;
186
187 // Category record word 1:
188 // 0:15 Reserved, value 0x0000.
189 categoryRecordOffset += uint16_t_size;
190 // 16:31 Number of events belonging to this category.
191 categories[categoryIndex].m_EventCount = profiling::ReadUint16(data, categoryRecordOffset);
192 categoryRecordOffset += uint16_t_size;
193
194 // Category record word 2
195 // 0:31 Offset from the beginning of the category data pool to the event_pointer_table
196 uint32_t eventPointerTableOffset = profiling::ReadUint32(data, categoryRecordOffset);
197 categoryRecordOffset += uint32_t_size;
198
199 // Category record word 3
200 // 0:31 Offset from the beginning of the category data pool to the name field.
201 uint32_t nameOffset = profiling::ReadUint32(data, categoryRecordOffset);
202 categoryRecordOffset += uint32_t_size;
203
204 //Get the events for the category
205 uint32_t eventCount = categories[categoryIndex].m_EventCount;
206
207 std::vector<uint32_t> eventRecordsOffsets(eventCount);
208
209 eventPointerTableOffset += categoryRecordOffset;
210
211 for (uint32_t eventIndex = 0; eventIndex < eventCount; ++eventIndex)
212 {
213 eventRecordsOffsets[eventIndex] =
214 profiling::ReadUint32(data, eventPointerTableOffset + uint32_t_size * eventIndex);
215 }
216
217 categories[categoryIndex].m_EventRecords = ReadEventRecords(data, categoryRecordOffset, eventRecordsOffsets);
218
219 categoryRecordOffset += uint32_t_size;
220
221 categories[categoryIndex].m_CategoryName = GetStringNameFromBuffer(data, categoryRecordOffset + nameOffset);
222 }
223
224 return categories;
225}
226
227
228std::vector<EventRecord> DirectoryCaptureCommandHandler::ReadEventRecords(const unsigned char* const data,
229 uint32_t offset,
230 std::vector<uint32_t> eventRecordsOffsets)
231{
232 uint32_t eventCount = static_cast<uint32_t>(eventRecordsOffsets.size());
233
234 std::vector<EventRecord> eventRecords(eventCount);
235 for (unsigned long i = 0; i < eventCount; ++i)
236 {
237 uint32_t eventRecordOffset = eventRecordsOffsets[i] + offset;
238
239 // Event record word 0:
240 // 0:15 [16] count_uid: unique ID for the counter. Must be unique across all counters in all categories
241 eventRecords[i].m_CounterUid = profiling::ReadUint16(data, eventRecordOffset);
242 eventRecordOffset += uint16_t_size;
243 // 16:31 [16] max_counter_uid: if the device this event is associated with has more than one core and there
244 // is one of these counters per core this value will be set to
245 // (counter_uid + cores (from device_record)) - 1.
246 // If there is only a single core then this value will be the same as
247 // the counter_uid value
248 eventRecords[i].m_MaxCounterUid = profiling::ReadUint16(data, eventRecordOffset);
249 eventRecordOffset += uint16_t_size;
250
251 // Event record word 1:
252 // 0:15 [16] counter_set: UID of the counter_set this event is associated with. Set to zero if the event
253 // is NOT associated with a counter_set
254 eventRecords[i].m_DeviceUid = profiling::ReadUint16(data, eventRecordOffset);
255 eventRecordOffset += uint16_t_size;
256
257 // 16:31 [16] device: UID of the device this event is associated with. Set to zero if the event is NOT
258 // associated with a device
259 eventRecords[i].m_CounterSetUid = profiling::ReadUint16(data, eventRecordOffset);
260 eventRecordOffset += uint16_t_size;
261
262 // Event record word 2:
263 // 0:15 [16] interpolation: type describing how to interpolate each data point in a stream of data points
264 eventRecords[i].m_CounterClass =profiling::ReadUint16(data, eventRecordOffset);
265 eventRecordOffset += uint16_t_size;
266
267 // 16:31 [16] class: type describing how to treat each data point in a stream of data points
268 eventRecords[i].m_CounterInterpolation = profiling::ReadUint16(data, eventRecordOffset);
269 eventRecordOffset += uint16_t_size;
270
271 // Event record word 3-4:
272 // 0:63 [64] multiplier: internal data stream is represented as integer values, this allows scaling of
273 // those values as if they are fixed point numbers. Zero is not a valid value
274 uint32_t multiplier[2] = { 0u, 0u };
275
276 multiplier[0] = profiling::ReadUint32(data, eventRecordOffset);
277 eventRecordOffset += uint32_t_size;
278 multiplier[1] = profiling::ReadUint32(data, eventRecordOffset);
279 eventRecordOffset += uint32_t_size;
280
281 std::memcpy(&eventRecords[i].m_CounterMultiplier, &multiplier, sizeof(multiplier));
282
283 // Event record word 5:
284 // 0:31 [32] name_eventRecordOffset: eventRecordOffset from the
285 // beginning of the event record pool to the name field
286 // The eventRecordOffset is always zero here, as the name field is always the first item in the pool
287 eventRecordOffset += uint32_t_size;
288
289 // Event record word 6:
290 // 0:31 [32] description_eventRecordOffset: eventRecordOffset from the
291 // beginning of the event record pool to the description field
292 // The size of the name buffer in bytes
293 uint32_t descriptionOffset = profiling::ReadUint32(data, eventRecordOffset);
294 eventRecordOffset += uint32_t_size;
295
296 // Event record word 7:
297 // 0:31 [32] units_eventRecordOffset: (optional) eventRecordOffset from the
298 // beginning of the event record pool to the units field.
299 // An eventRecordOffset value of zero indicates this field is not provided
300 uint32_t unitsOffset = profiling::ReadUint32(data, eventRecordOffset);
301 eventRecordOffset += uint32_t_size;
302 eventRecordOffset += uint32_t_size;
303
304 eventRecords[i].m_CounterName = GetStringNameFromBuffer(data, eventRecordOffset);
305
306 eventRecords[i].m_CounterDescription = GetStringNameFromBuffer(data, eventRecordOffset + descriptionOffset);
307
308 eventRecords[i].m_CounterUnits = GetStringNameFromBuffer(data, eventRecordOffset + unitsOffset);
309 }
310
311 return eventRecords;
312}
313
314void DirectoryCaptureCommandHandler::operator()(const profiling::Packet& packet)
315{
316 if (!m_QuietOperation)// Are we supposed to print to stdout?
317 {
318 std::cout << "Counter directory packet received." << std::endl;
319 }
320
321 ParseData(packet);
322
323 if (!m_QuietOperation)
324 {
325 m_CounterDirectory.print();
326 }
327}
328
329CounterDirectory DirectoryCaptureCommandHandler::GetCounterDirectory() const
330{
331 return m_CounterDirectory;
332}
333
334uint32_t DirectoryCaptureCommandHandler::GetCounterDirectoryCount() const
335{
336 return m_CounterDirectoryCount.load(std::memory_order_acquire);
337}
338
339} // namespace gatordmock
340
341} // namespace armnn