1 //
2 // Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include <common/include/Assert.hpp>
7 #include <common/include/CommonProfilingUtils.hpp>
8 #include <common/include/ProfilingException.hpp>
9
10 #include <iostream>
11 #include <limits>
12 #include <sstream>
13
14 namespace arm
15 {
16
17 namespace pipe
18 {
ReadBytes(const unsigned char * buffer,unsigned int offset,unsigned int valueSize,uint8_t outValue[])19 void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
20 {
21 ARM_PIPE_ASSERT(buffer);
22 ARM_PIPE_ASSERT(outValue);
23
24 for (unsigned int i = 0; i < valueSize; i++, offset++)
25 {
26 outValue[i] = static_cast<uint8_t>(buffer[offset]);
27 }
28 }
29
ReadUint64(const unsigned char * buffer,unsigned int offset)30 uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
31 {
32 ARM_PIPE_ASSERT(buffer);
33
34 uint64_t value = 0;
35 value = static_cast<uint64_t>(buffer[offset]);
36 value |= static_cast<uint64_t>(buffer[offset + 1]) << 8;
37 value |= static_cast<uint64_t>(buffer[offset + 2]) << 16;
38 value |= static_cast<uint64_t>(buffer[offset + 3]) << 24;
39 value |= static_cast<uint64_t>(buffer[offset + 4]) << 32;
40 value |= static_cast<uint64_t>(buffer[offset + 5]) << 40;
41 value |= static_cast<uint64_t>(buffer[offset + 6]) << 48;
42 value |= static_cast<uint64_t>(buffer[offset + 7]) << 56;
43
44 return value;
45 }
46
ReadUint32(const unsigned char * buffer,unsigned int offset)47 uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset)
48 {
49 ARM_PIPE_ASSERT(buffer);
50
51 uint32_t value = 0;
52 value = static_cast<uint32_t>(buffer[offset]);
53 value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
54 value |= static_cast<uint32_t>(buffer[offset + 2]) << 16;
55 value |= static_cast<uint32_t>(buffer[offset + 3]) << 24;
56 return value;
57 }
58
ReadUint16(const unsigned char * buffer,unsigned int offset)59 uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset)
60 {
61 ARM_PIPE_ASSERT(buffer);
62
63 uint32_t value = 0;
64 value = static_cast<uint32_t>(buffer[offset]);
65 value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
66 return static_cast<uint16_t>(value);
67 }
68
ReadUint8(const unsigned char * buffer,unsigned int offset)69 uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset)
70 {
71 ARM_PIPE_ASSERT(buffer);
72
73 return buffer[offset];
74 }
75
WriteBytes(unsigned char * buffer,unsigned int offset,const void * value,unsigned int valueSize)76 void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize)
77 {
78 ARM_PIPE_ASSERT(buffer);
79 ARM_PIPE_ASSERT(value);
80
81 for (unsigned int i = 0; i < valueSize; i++, offset++)
82 {
83 buffer[offset] = *(reinterpret_cast<const unsigned char*>(value) + i);
84 }
85 }
86
WriteUint64(unsigned char * buffer,unsigned int offset,uint64_t value)87 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
88 {
89 ARM_PIPE_ASSERT(buffer);
90
91 buffer[offset] = static_cast<unsigned char>(value & 0xFF);
92 buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
93 buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
94 buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
95 buffer[offset + 4] = static_cast<unsigned char>((value >> 32) & 0xFF);
96 buffer[offset + 5] = static_cast<unsigned char>((value >> 40) & 0xFF);
97 buffer[offset + 6] = static_cast<unsigned char>((value >> 48) & 0xFF);
98 buffer[offset + 7] = static_cast<unsigned char>((value >> 56) & 0xFF);
99 }
100
WriteUint32(unsigned char * buffer,unsigned int offset,uint32_t value)101 void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value)
102 {
103 ARM_PIPE_ASSERT(buffer);
104
105 buffer[offset] = static_cast<unsigned char>(value & 0xFF);
106 buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
107 buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
108 buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
109 }
110
WriteUint16(unsigned char * buffer,unsigned int offset,uint16_t value)111 void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value)
112 {
113 ARM_PIPE_ASSERT(buffer);
114
115 buffer[offset] = static_cast<unsigned char>(value & 0xFF);
116 buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
117 }
118
WriteUint8(unsigned char * buffer,unsigned int offset,uint8_t value)119 void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value)
120 {
121 ARM_PIPE_ASSERT(buffer);
122
123 buffer[offset] = static_cast<unsigned char>(value);
124 }
125
CentreAlignFormatting(const std::string & stringToPass,const int spacingWidth)126 std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
127 {
128 std::stringstream outputStream, centrePadding;
129 int padding = spacingWidth - static_cast<int>(stringToPass.size());
130
131 for (int i = 0; i < padding / 2; ++i)
132 {
133 centrePadding << " ";
134 }
135
136 outputStream << centrePadding.str() << stringToPass << centrePadding.str();
137
138 if (padding > 0 && padding %2 != 0)
139 {
140 outputStream << " ";
141 }
142
143 return outputStream.str();
144 }
145
PrintDeviceDetails(const std::pair<const unsigned short,std::unique_ptr<Device>> & devicePair)146 void PrintDeviceDetails(const std::pair<const unsigned short, std::unique_ptr<Device>>& devicePair)
147 {
148 std::string body;
149
150 body.append(CentreAlignFormatting(devicePair.second->m_Name, 20));
151 body.append(" | ");
152 body.append(CentreAlignFormatting(std::to_string(devicePair.first), 13));
153 body.append(" | ");
154 body.append(CentreAlignFormatting(std::to_string(devicePair.second->m_Cores), 10));
155 body.append("\n");
156
157 std::cout << std::string(body.size(), '-') << "\n";
158 std::cout<< body;
159 }
160
PrintCounterSetDetails(const std::pair<const unsigned short,std::unique_ptr<CounterSet>> & counterSetPair)161 void PrintCounterSetDetails(const std::pair<const unsigned short, std::unique_ptr<CounterSet>>& counterSetPair)
162 {
163 std::string body;
164
165 body.append(CentreAlignFormatting(counterSetPair.second->m_Name, 20));
166 body.append(" | ");
167 body.append(CentreAlignFormatting(std::to_string(counterSetPair.first), 13));
168 body.append(" | ");
169 body.append(CentreAlignFormatting(std::to_string(counterSetPair.second->m_Count), 10));
170 body.append("\n");
171
172 std::cout << std::string(body.size(), '-') << "\n";
173
174 std::cout<< body;
175 }
176
PrintCounterDetails(std::shared_ptr<Counter> & counter)177 void PrintCounterDetails(std::shared_ptr<Counter>& counter)
178 {
179 std::string body;
180
181 body.append(CentreAlignFormatting(counter->m_Name, 20));
182 body.append(" | ");
183 body.append(CentreAlignFormatting(counter->m_Description, 50));
184 body.append(" | ");
185 body.append(CentreAlignFormatting(counter->m_Units, 14));
186 body.append(" | ");
187 body.append(CentreAlignFormatting(std::to_string(counter->m_Uid), 6));
188 body.append(" | ");
189 body.append(CentreAlignFormatting(std::to_string(counter->m_MaxCounterUid), 10));
190 body.append(" | ");
191 body.append(CentreAlignFormatting(std::to_string(counter->m_Class), 8));
192 body.append(" | ");
193 body.append(CentreAlignFormatting(std::to_string(counter->m_Interpolation), 14));
194 body.append(" | ");
195 body.append(CentreAlignFormatting(std::to_string(counter->m_Multiplier), 20));
196 body.append(" | ");
197 body.append(CentreAlignFormatting(std::to_string(counter->m_CounterSetUid), 16));
198 body.append(" | ");
199 body.append(CentreAlignFormatting(std::to_string(counter->m_DeviceUid), 14));
200
201 body.append("\n");
202
203 std::cout << std::string(body.size(), '-') << "\n";
204
205 std::cout << body;
206 }
207
PrintCategoryDetails(const std::unique_ptr<Category> & category,std::unordered_map<unsigned short,std::shared_ptr<Counter>> counterMap)208 void PrintCategoryDetails(const std::unique_ptr<Category>& category,
209 std::unordered_map<unsigned short, std::shared_ptr<Counter>> counterMap)
210 {
211 std::string categoryBody;
212 std::string categoryHeader;
213
214 categoryHeader.append(CentreAlignFormatting("Name", 20));
215 categoryHeader.append(" | ");
216 categoryHeader.append(CentreAlignFormatting("Event Count", 14));
217 categoryHeader.append("\n");
218
219 categoryBody.append(CentreAlignFormatting(category->m_Name, 20));
220 categoryBody.append(" | ");
221 categoryBody.append(CentreAlignFormatting(std::to_string(category->m_Counters.size()), 14));
222
223 std::cout << "\n" << "\n";
224 std::cout << CentreAlignFormatting("CATEGORY", static_cast<int>(categoryHeader.size()));
225 std::cout << "\n";
226 std::cout << std::string(categoryHeader.size(), '=') << "\n";
227
228 std::cout << categoryHeader;
229
230 std::cout << std::string(categoryBody.size(), '-') << "\n";
231
232 std::cout << categoryBody;
233
234 std::string counterHeader;
235
236 counterHeader.append(CentreAlignFormatting("Counter Name", 20));
237 counterHeader.append(" | ");
238 counterHeader.append(CentreAlignFormatting("Description", 50));
239 counterHeader.append(" | ");
240 counterHeader.append(CentreAlignFormatting("Units", 14));
241 counterHeader.append(" | ");
242 counterHeader.append(CentreAlignFormatting("UID", 6));
243 counterHeader.append(" | ");
244 counterHeader.append(CentreAlignFormatting("Max UID", 10));
245 counterHeader.append(" | ");
246 counterHeader.append(CentreAlignFormatting("Class", 8));
247 counterHeader.append(" | ");
248 counterHeader.append(CentreAlignFormatting("Interpolation", 14));
249 counterHeader.append(" | ");
250 counterHeader.append(CentreAlignFormatting("Multiplier", 20));
251 counterHeader.append(" | ");
252 counterHeader.append(CentreAlignFormatting("Counter set UID", 16));
253 counterHeader.append(" | ");
254 counterHeader.append(CentreAlignFormatting("Device UID", 14));
255 counterHeader.append("\n");
256
257 std::cout << "\n" << "\n";
258 std::cout << CentreAlignFormatting("EVENTS IN CATEGORY: " + category->m_Name,
259 static_cast<int>(counterHeader.size()));
260 std::cout << "\n";
261 std::cout << std::string(counterHeader.size(), '=') << "\n";
262 std::cout << counterHeader;
263 for (auto& it: category->m_Counters) {
264 auto search = counterMap.find(it);
265 if(search != counterMap.end()) {
266 PrintCounterDetails(search->second);
267 }
268 }
269 }
270
PrintCounterDirectory(ICounterDirectory & counterDirectory)271 void PrintCounterDirectory(ICounterDirectory& counterDirectory)
272 {
273 std::string devicesHeader;
274
275 devicesHeader.append(CentreAlignFormatting("Device name", 20));
276 devicesHeader.append(" | ");
277 devicesHeader.append(CentreAlignFormatting("UID", 13));
278 devicesHeader.append(" | ");
279 devicesHeader.append(CentreAlignFormatting("Cores", 10));
280 devicesHeader.append("\n");
281
282 std::cout << "\n" << "\n";
283 std::cout << CentreAlignFormatting("DEVICES", static_cast<int>(devicesHeader.size()));
284 std::cout << "\n";
285 std::cout << std::string(devicesHeader.size(), '=') << "\n";
286 std::cout << devicesHeader;
287 for (auto& it: counterDirectory.GetDevices()) {
288 PrintDeviceDetails(it);
289 }
290
291 std::string counterSetHeader;
292
293 counterSetHeader.append(CentreAlignFormatting("Counter set name", 20));
294 counterSetHeader.append(" | ");
295 counterSetHeader.append(CentreAlignFormatting("UID", 13));
296 counterSetHeader.append(" | ");
297 counterSetHeader.append(CentreAlignFormatting("Count", 10));
298 counterSetHeader.append("\n");
299
300 std::cout << "\n" << "\n";
301 std::cout << CentreAlignFormatting("COUNTER SETS", static_cast<int>(counterSetHeader.size()));
302 std::cout << "\n";
303 std::cout << std::string(counterSetHeader.size(), '=') << "\n";
304
305 std::cout << counterSetHeader;
306
307 for (auto& it: counterDirectory.GetCounterSets()) {
308 PrintCounterSetDetails(it);
309 }
310
311 auto counters = counterDirectory.GetCounters();
312 for (auto& it: counterDirectory.GetCategories()) {
313 PrintCategoryDetails(it, counters);
314 }
315 std::cout << "\n";
316 }
317
318 namespace
319 {
320
ThrowIfCantGenerateNextUid(uint16_t uid,uint16_t cores=0)321 void ThrowIfCantGenerateNextUid(uint16_t uid, uint16_t cores = 0)
322 {
323 // Check that it is possible to generate the next UID without causing an overflow
324 switch (cores)
325 {
326 case 0:
327 case 1:
328 // Number of cores not specified or set to 1 (a value of zero indicates the device is not capable of
329 // running multiple parallel workloads and will not provide multiple streams of data for each event)
330 if (uid == std::numeric_limits<uint16_t>::max())
331 {
332 throw arm::pipe::ProfilingException("Generating the next UID for profiling would result in an overflow");
333 }
334 break;
335 default: // cores > 1
336 // Multiple cores available, as max_counter_uid has to be set to: counter_uid + cores - 1, the maximum
337 // allowed value for a counter UID is consequently: uint16_t_max - cores + 1
338 if (uid >= std::numeric_limits<uint16_t>::max() - cores + 1)
339 {
340 throw arm::pipe::ProfilingException("Generating the next UID for profiling would result in an overflow");
341 }
342 break;
343 }
344 }
345
346 } // Anonymous namespace
347
GetNextUid(bool peekOnly)348 uint16_t GetNextUid(bool peekOnly)
349 {
350 // The UID used for profiling objects and events. The first valid UID is 1, as 0 is a reserved value
351 static uint16_t uid = 1;
352
353 // Check that it is possible to generate the next UID without causing an overflow (throws in case of error)
354 ThrowIfCantGenerateNextUid(uid);
355
356 if (peekOnly)
357 {
358 // Peek only
359 return uid;
360 }
361 else
362 {
363 // Get the next UID
364 return uid++;
365 }
366 }
367
GetNextCounterUids(uint16_t firstUid,uint16_t cores)368 std::vector<uint16_t> GetNextCounterUids(uint16_t firstUid, uint16_t cores)
369 {
370 // Check that it is possible to generate the next counter UID without causing an overflow (throws in case of error)
371 ThrowIfCantGenerateNextUid(firstUid, cores);
372
373 // Get the next counter UIDs
374 size_t counterUidsSize = cores == 0 ? 1 : cores;
375 std::vector<uint16_t> counterUids(counterUidsSize, 0);
376 for (size_t i = 0; i < counterUidsSize; i++)
377 {
378 counterUids[i] = firstUid++;
379 }
380 return counterUids;
381 }
382
383 } // namespace pipe
384 } // namespace arm
385