• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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