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