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