xref: /aosp_15_r20/external/armnn/profiling/common/src/CounterDirectory.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <common/include/CounterDirectory.hpp>
7 #include <common/include/CommonProfilingUtils.hpp>
8 
9 #include <common/include/Assert.hpp>
10 #include <common/include/SwTrace.hpp>
11 
12 #include <fmt/format.h>
13 
14 namespace arm
15 {
16 
17 namespace pipe
18 {
19 
RegisterCategory(const std::string & categoryName)20 const Category* CounterDirectory::RegisterCategory(const std::string& categoryName)
21 {
22     // Check that the given category name is valid
23     if (categoryName.empty() ||
24             !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>(categoryName))
25     {
26         throw arm::pipe::InvalidArgumentException("Trying to register a category with an invalid name");
27     }
28 
29     // Check that the given category is not already registered
30     if (IsCategoryRegistered(categoryName))
31     {
32         throw arm::pipe::InvalidArgumentException(fmt::format(
33             "Trying to register a category already registered (\"{}\")",
34             categoryName));
35     }
36 
37     // Create the category
38     CategoryPtr category = std::make_unique<Category>(categoryName);
39     ARM_PIPE_ASSERT(category);
40 
41     // Get the raw category pointer
42     const Category* categoryPtr = category.get();
43     ARM_PIPE_ASSERT(categoryPtr);
44 
45     // Register the category
46     m_Categories.insert(std::move(category));
47 
48     return categoryPtr;
49 }
50 
RegisterDevice(const std::string & deviceName,uint16_t cores,const arm::pipe::Optional<std::string> & parentCategoryName)51 const Device* CounterDirectory::RegisterDevice(const std::string& deviceName,
52                                                uint16_t cores,
53                                                const arm::pipe::Optional<std::string>& parentCategoryName)
54 {
55     // Check that the given device name is valid
56     if (deviceName.empty() ||
57             !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>(deviceName))
58     {
59         throw arm::pipe::InvalidArgumentException("Trying to register a device with an invalid name");
60     }
61 
62     // Check that a device with the given name is not already registered
63     if (IsDeviceRegistered(deviceName))
64     {
65         throw arm::pipe::InvalidArgumentException(fmt::format(
66             "Trying to register a device already registered (\"{}\")",
67             deviceName));
68     }
69 
70     // Check that a category with the given (optional) parent category name is already registered
71     if (parentCategoryName.has_value())
72     {
73         // Get the (optional) parent category name
74         const std::string& parentCategoryNameValue = parentCategoryName.value();
75         if (parentCategoryNameValue.empty())
76         {
77             throw arm::pipe::InvalidArgumentException(
78                 fmt::format("Trying to connect a device (name: \"{}\") to an invalid "
79                             "parent category (name: \"{}\")",
80                             deviceName,
81                             parentCategoryNameValue));
82         }
83 
84         // Check that the given parent category is already registered
85         auto categoryIt = FindCategory(parentCategoryNameValue);
86         if (categoryIt == m_Categories.end())
87         {
88             throw arm::pipe::InvalidArgumentException(
89                 fmt::format("Trying to connect a device (name: \"{}\") to a parent category that "
90                             "is not registered (name: \"{}\")",
91                             deviceName,
92                             parentCategoryNameValue));
93         }
94     }
95 
96     // Get the device UID
97     uint16_t deviceUid = GetNextUid();
98 
99     // Create the device
100     DevicePtr device = std::make_unique<Device>(deviceUid, deviceName, cores);
101     ARM_PIPE_ASSERT(device);
102 
103     // Get the raw device pointer
104     const Device* devicePtr = device.get();
105     ARM_PIPE_ASSERT(devicePtr);
106 
107     // Register the device
108     m_Devices.insert(std::make_pair(deviceUid, std::move(device)));
109 
110     return devicePtr;
111 }
112 
RegisterCounterSet(const std::string & counterSetName,uint16_t count,const arm::pipe::Optional<std::string> & parentCategoryName)113 const CounterSet* CounterDirectory::RegisterCounterSet(const std::string& counterSetName,
114                                                        uint16_t count,
115                                                        const arm::pipe::Optional<std::string>& parentCategoryName)
116 {
117     // Check that the given counter set name is valid
118     if (counterSetName.empty() ||
119             !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>(counterSetName))
120     {
121         throw arm::pipe::InvalidArgumentException("Trying to register a counter set with an invalid name");
122     }
123 
124     // Check that a counter set with the given name is not already registered
125     if (IsCounterSetRegistered(counterSetName))
126     {
127         throw arm::pipe::InvalidArgumentException(
128             fmt::format("Trying to register a counter set already registered (\"{}\")", counterSetName));
129     }
130 
131     // Peek the next UID, do not get an actual valid UID just now as we don't want to waste a good UID in case
132     // the registration fails. We'll get a proper one once we're sure that the counter set can be registered
133     uint16_t counterSetUidPeek = GetNextUid(true);
134 
135     // Check that a category with the given (optional) parent category name is already registered
136     if (parentCategoryName.has_value())
137     {
138         // Get the (optional) parent category name
139         const std::string& parentCategoryNameValue = parentCategoryName.value();
140         if (parentCategoryNameValue.empty())
141         {
142             throw arm::pipe::InvalidArgumentException(
143                 fmt::format("Trying to connect a counter set (UID: {}) to an invalid "
144                                     "parent category (name: \"{}\")",
145                                     counterSetUidPeek,
146                                     parentCategoryNameValue));
147         }
148 
149         // Check that the given parent category is already registered
150         auto it = FindCategory(parentCategoryNameValue);
151         if (it == m_Categories.end())
152         {
153             throw arm::pipe::InvalidArgumentException(
154                 fmt::format("Trying to connect a counter set (UID: {}) to a parent category "
155                             "that is not registered (name: \"{}\")",
156                             counterSetUidPeek,
157                             parentCategoryNameValue));
158         }
159     }
160 
161     // Get the counter set UID
162     uint16_t counterSetUid = GetNextUid();
163     ARM_PIPE_ASSERT(counterSetUid == counterSetUidPeek);
164 
165     // Create the counter set
166     CounterSetPtr counterSet = std::make_unique<CounterSet>(counterSetUid, counterSetName, count);
167     ARM_PIPE_ASSERT(counterSet);
168 
169     // Get the raw counter set pointer
170     const CounterSet* counterSetPtr = counterSet.get();
171     ARM_PIPE_ASSERT(counterSetPtr);
172 
173     // Register the counter set
174     m_CounterSets.insert(std::make_pair(counterSetUid, std::move(counterSet)));
175 
176     return counterSetPtr;
177 }
178 
RegisterCounter(const std::string & applicationName,const uint16_t uid,const std::string & parentCategoryName,uint16_t counterClass,uint16_t interpolation,double multiplier,const std::string & name,const std::string & description,const arm::pipe::Optional<std::string> & units,const arm::pipe::Optional<uint16_t> & numberOfCores,const arm::pipe::Optional<uint16_t> & deviceUid,const arm::pipe::Optional<uint16_t> & counterSetUid)179 const Counter* CounterDirectory::RegisterCounter(const std::string& applicationName,
180                                                  const uint16_t uid,
181                                                  const std::string& parentCategoryName,
182                                                  uint16_t counterClass,
183                                                  uint16_t interpolation,
184                                                  double multiplier,
185                                                  const std::string& name,
186                                                  const std::string& description,
187                                                  const arm::pipe::Optional<std::string>& units,
188                                                  const arm::pipe::Optional<uint16_t>& numberOfCores,
189                                                  const arm::pipe::Optional<uint16_t>& deviceUid,
190                                                  const arm::pipe::Optional<uint16_t>& counterSetUid)
191 {
192     // Check that the given parent category name is valid
193     if (parentCategoryName.empty() ||
194             !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>(parentCategoryName))
195     {
196         throw arm::pipe::InvalidArgumentException("Trying to register a counter with an invalid parent category name");
197     }
198 
199     // Check that the given class is valid
200     if (counterClass != 0 && counterClass != 1)
201     {
202         throw arm::pipe::InvalidArgumentException("Trying to register a counter with an invalid class");
203     }
204 
205     // Check that the given interpolation is valid
206     if (interpolation != 0 && interpolation != 1)
207     {
208         throw arm::pipe::InvalidArgumentException("Trying to register a counter with an invalid interpolation");
209     }
210 
211     // Check that the given multiplier is valid
212     if (multiplier == .0f)
213     {
214         throw arm::pipe::InvalidArgumentException("Trying to register a counter with an invalid multiplier");
215     }
216 
217     // Check that the given name is valid
218     if (name.empty() ||
219             !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>(name))
220     {
221         throw arm::pipe::InvalidArgumentException("Trying to register a counter with an invalid name");
222     }
223 
224     // Check that the given description is valid
225     if (description.empty() ||
226             !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceCharPolicy>(description))
227     {
228         throw arm::pipe::InvalidArgumentException("Trying to register a counter with an invalid description");
229     }
230 
231     // Check that the given units are valid
232     if (units.has_value()
233             && !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>(units.value()))
234     {
235         throw arm::pipe::InvalidArgumentException("Trying to register a counter with a invalid units");
236     }
237 
238     // Check that the given parent category is registered
239     auto categoryIt = FindCategory(parentCategoryName);
240     if (categoryIt == m_Categories.end())
241     {
242         throw arm::pipe::InvalidArgumentException(
243             fmt::format("Trying to connect a counter to a category that is not registered (name: \"{}\")",
244                         parentCategoryName));
245     }
246 
247     // Get the parent category
248     const CategoryPtr& parentCategory = *categoryIt;
249     ARM_PIPE_ASSERT(parentCategory);
250 
251     // Check that a counter with the given name is not already registered within the parent category
252     const std::vector<uint16_t>& parentCategoryCounters = parentCategory->m_Counters;
253     for (uint16_t parentCategoryCounterUid : parentCategoryCounters)
254     {
255         const Counter* parentCategoryCounter = GetCounter(parentCategoryCounterUid);
256         ARM_PIPE_ASSERT(parentCategoryCounter);
257 
258         if (parentCategoryCounter->m_Name == name)
259         {
260             throw arm::pipe::InvalidArgumentException(
261                 fmt::format("Trying to register a counter to category \"{}\" with a name that "
262                             "is already used within that category (name: \"{}\")",
263                             parentCategoryName,
264                             name));
265         }
266     }
267 
268     // Check that a counter set with the given (optional) UID is already registered
269     uint16_t counterSetUidValue = counterSetUid.has_value() ? counterSetUid.value() : 0;
270     if (counterSetUidValue > 0)
271     {
272         // Check that the (optional) counter set is already registered
273         if (!IsCounterSetRegistered(counterSetUidValue))
274         {
275             throw InvalidArgumentException(
276                         fmt::format("Trying to connect a counter to a counter set that is "
277                                     "not registered (counter set UID: {})",
278                                     counterSetUidValue));
279         }
280     }
281 
282     // Get the number of cores (this call may throw)
283     uint16_t deviceUidValue = deviceUid.has_value() ? deviceUid.value() : 0;
284     uint16_t deviceCores = GetNumberOfCores(numberOfCores, deviceUidValue);
285 
286     // Get the counter UIDs and calculate the max counter UID
287     std::vector<uint16_t> counterUids = GetNextCounterUids(uid, deviceCores);
288     ARM_PIPE_ASSERT(!counterUids.empty());
289     uint16_t maxCounterUid = deviceCores <= 1 ? counterUids.front() : counterUids.back();
290 
291     // Get the counter units
292     const std::string unitsValue = units.has_value() ? units.value() : "";
293 
294     // Create the counter
295     CounterPtr counter = std::make_shared<Counter>(applicationName,
296                                                    counterUids.front(),
297                                                    maxCounterUid,
298                                                    counterClass,
299                                                    interpolation,
300                                                    multiplier,
301                                                    name,
302                                                    description,
303                                                    unitsValue,
304                                                    deviceUidValue,
305                                                    counterSetUidValue);
306     ARM_PIPE_ASSERT(counter);
307 
308     // Get the raw counter pointer
309     const Counter* counterPtr = counter.get();
310     ARM_PIPE_ASSERT(counterPtr);
311 
312     // Process multiple counters if necessary
313     for (uint16_t counterUid : counterUids)
314     {
315         // Connect the counter to the parent category
316         parentCategory->m_Counters.push_back(counterUid);
317 
318         // Register the counter
319         m_Counters.insert(std::make_pair(counterUid, counter));
320     }
321 
322     return counterPtr;
323 }
324 
GetCategory(const std::string & categoryName) const325 const Category* CounterDirectory::GetCategory(const std::string& categoryName) const
326 {
327     auto it = FindCategory(categoryName);
328     if (it == m_Categories.end())
329     {
330         return nullptr;
331     }
332 
333     const Category* category = it->get();
334     ARM_PIPE_ASSERT(category);
335 
336     return category;
337 }
338 
GetDevice(uint16_t deviceUid) const339 const Device* CounterDirectory::GetDevice(uint16_t deviceUid) const
340 {
341     auto it = FindDevice(deviceUid);
342     if (it == m_Devices.end())
343     {
344         return nullptr;
345     }
346 
347     const Device* device = it->second.get();
348     ARM_PIPE_ASSERT(device);
349     ARM_PIPE_ASSERT(device->m_Uid == deviceUid);
350 
351     return device;
352 }
353 
GetCounterSet(uint16_t counterSetUid) const354 const CounterSet* CounterDirectory::GetCounterSet(uint16_t counterSetUid) const
355 {
356     auto it = FindCounterSet(counterSetUid);
357     if (it == m_CounterSets.end())
358     {
359         return nullptr;
360     }
361 
362     const CounterSet* counterSet = it->second.get();
363     ARM_PIPE_ASSERT(counterSet);
364     ARM_PIPE_ASSERT(counterSet->m_Uid == counterSetUid);
365 
366     return counterSet;
367 }
368 
GetCounter(uint16_t counterUid) const369 const Counter* CounterDirectory::GetCounter(uint16_t counterUid) const
370 {
371     auto it = FindCounter(counterUid);
372     if (it == m_Counters.end())
373     {
374         return nullptr;
375     }
376 
377     const Counter* counter = it->second.get();
378     ARM_PIPE_ASSERT(counter);
379     ARM_PIPE_ASSERT(counter->m_Uid <= counterUid);
380     ARM_PIPE_ASSERT(counter->m_Uid <= counter->m_MaxCounterUid);
381 
382     return counter;
383 }
384 
IsCategoryRegistered(const std::string & categoryName) const385 bool CounterDirectory::IsCategoryRegistered(const std::string& categoryName) const
386 {
387     auto it = FindCategory(categoryName);
388 
389     return it != m_Categories.end();
390 }
391 
IsDeviceRegistered(uint16_t deviceUid) const392 bool CounterDirectory::IsDeviceRegistered(uint16_t deviceUid) const
393 {
394     auto it = FindDevice(deviceUid);
395 
396     return it != m_Devices.end();
397 }
398 
IsDeviceRegistered(const std::string & deviceName) const399 bool CounterDirectory::IsDeviceRegistered(const std::string& deviceName) const
400 {
401     auto it = FindDevice(deviceName);
402 
403     return it != m_Devices.end();
404 }
405 
IsCounterSetRegistered(uint16_t counterSetUid) const406 bool CounterDirectory::IsCounterSetRegistered(uint16_t counterSetUid) const
407 {
408     auto it = FindCounterSet(counterSetUid);
409 
410     return it != m_CounterSets.end();
411 }
412 
IsCounterSetRegistered(const std::string & counterSetName) const413 bool CounterDirectory::IsCounterSetRegistered(const std::string& counterSetName) const
414 {
415     auto it = FindCounterSet(counterSetName);
416 
417     return it != m_CounterSets.end();
418 }
419 
IsCounterRegistered(uint16_t counterUid) const420 bool CounterDirectory::IsCounterRegistered(uint16_t counterUid) const
421 {
422     auto it = FindCounter(counterUid);
423 
424     return it != m_Counters.end();
425 }
426 
IsCounterRegistered(const std::string & counterName) const427 bool CounterDirectory::IsCounterRegistered(const std::string& counterName) const
428 {
429     auto it = FindCounter(counterName);
430 
431     return it != m_Counters.end();
432 }
433 
Clear()434 void CounterDirectory::Clear()
435 {
436     // Clear all the counter directory contents
437     m_Categories.clear();
438     m_Devices.clear();
439     m_CounterSets.clear();
440     m_Counters.clear();
441 }
442 
FindCategory(const std::string & categoryName) const443 CategoriesIt CounterDirectory::FindCategory(const std::string& categoryName) const
444 {
445     return std::find_if(m_Categories.begin(), m_Categories.end(), [&categoryName](const CategoryPtr& category)
446     {
447         ARM_PIPE_ASSERT(category);
448 
449         return category->m_Name == categoryName;
450     });
451 }
452 
FindDevice(uint16_t deviceUid) const453 DevicesIt CounterDirectory::FindDevice(uint16_t deviceUid) const
454 {
455     return m_Devices.find(deviceUid);
456 }
457 
FindDevice(const std::string & deviceName) const458 DevicesIt CounterDirectory::FindDevice(const std::string& deviceName) const
459 {
460     return std::find_if(m_Devices.begin(), m_Devices.end(), [&deviceName](const auto& pair)
461     {
462         ARM_PIPE_ASSERT(pair.second);
463         ARM_PIPE_ASSERT(pair.second->m_Uid == pair.first);
464 
465         return pair.second->m_Name == deviceName;
466     });
467 }
468 
FindCounterSet(uint16_t counterSetUid) const469 CounterSetsIt CounterDirectory::FindCounterSet(uint16_t counterSetUid) const
470 {
471     return m_CounterSets.find(counterSetUid);
472 }
473 
FindCounterSet(const std::string & counterSetName) const474 CounterSetsIt CounterDirectory::FindCounterSet(const std::string& counterSetName) const
475 {
476     return std::find_if(m_CounterSets.begin(), m_CounterSets.end(), [&counterSetName](const auto& pair)
477     {
478         ARM_PIPE_ASSERT(pair.second);
479         ARM_PIPE_ASSERT(pair.second->m_Uid == pair.first);
480 
481         return pair.second->m_Name == counterSetName;
482     });
483 }
484 
FindCounter(uint16_t counterUid) const485 CountersIt CounterDirectory::FindCounter(uint16_t counterUid) const
486 {
487     return m_Counters.find(counterUid);
488 }
489 
FindCounter(const std::string & counterName) const490 CountersIt CounterDirectory::FindCounter(const std::string& counterName) const
491 {
492     return std::find_if(m_Counters.begin(), m_Counters.end(), [&counterName](const auto& pair)
493     {
494         ARM_PIPE_ASSERT(pair.second);
495         ARM_PIPE_ASSERT(pair.first >= pair.second->m_Uid && pair.first <= pair.second->m_MaxCounterUid);
496 
497         return pair.second->m_Name == counterName;
498     });
499 }
500 
GetNumberOfCores(const arm::pipe::Optional<uint16_t> & numberOfCores,uint16_t deviceUid)501 uint16_t CounterDirectory::GetNumberOfCores(const arm::pipe::Optional<uint16_t>& numberOfCores,
502                                             uint16_t deviceUid)
503 {
504     // To get the number of cores, apply the following rules:
505     //
506     // 1. If numberOfCores is set then take it as the deviceCores value
507     // 2. If numberOfCores is not set then check to see if this counter is directly associated with a device,
508     //    if so then that devices number of cores is taken as the deviceCores value
509     // 3. If none of the above holds then set deviceCores to zero
510 
511     // 1. If numberOfCores is set then take it as the deviceCores value
512     if (numberOfCores.has_value())
513     {
514         // Get the number of cores
515         return numberOfCores.value();
516     }
517 
518     // 2. If numberOfCores is not set then check to see if this counter is directly associated with a device,
519     //    if so then that devices number of cores is taken as the deviceCores value
520     if (deviceUid > 0)
521     {
522         // Check that the (optional) device is already registered
523         auto deviceIt = FindDevice(deviceUid);
524         if (deviceIt == m_Devices.end())
525         {
526             throw arm::pipe::InvalidArgumentException(
527                 fmt::format("Trying to connect a counter to a device that is not registered (device UID {})",
528                             deviceUid));
529         }
530 
531         // Get the associated device
532         const DevicePtr& device = deviceIt->second;
533         ARM_PIPE_ASSERT(device);
534 
535 
536         // Get the number of cores of the associated device
537         return device->m_Cores;
538     }
539 
540     // 3. If none of the above holds then set deviceCores to zero
541     return 0;
542 }
543 
544 } // namespace pipe
545 
546 } // namespace arm
547