ArmNN
 20.11
CounterDirectory.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. 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/utility/Assert.hpp>
12 
13 #include <common/include/SwTrace.hpp>
14 
15 #include <fmt/format.h>
16 
17 namespace armnn
18 {
19 
20 namespace profiling
21 {
22 
23 const Category* CounterDirectory::RegisterCategory(const std::string& categoryName)
24 {
25  // Check that the given category name is valid
26  if (categoryName.empty() ||
27  !arm::pipe::IsValidSwTraceString<arm::pipe::SwTraceNameCharPolicy>(categoryName))
28  {
29  throw InvalidArgumentException("Trying to register a category with an invalid name");
30  }
31 
32  // Check that the given category is not already registered
33  if (IsCategoryRegistered(categoryName))
34  {
35  throw InvalidArgumentException(fmt::format("Trying to register a category already registered (\"{}\")",
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  !arm::pipe::IsValidSwTraceString<arm::pipe::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  {
67  throw InvalidArgumentException(fmt::format("Trying to register a device already registered (\"{}\")",
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  fmt::format("Trying to connect a device (name: \"{}\") to an invalid "
80  "parent category (name: \"{}\")",
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  fmt::format("Trying to connect a device (name: \"{}\") to a parent category that "
91  "is not registered (name: \"{}\")",
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  ARMNN_ASSERT(device);
103 
104  // Get the raw device pointer
105  const Device* devicePtr = device.get();
106  ARMNN_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  !arm::pipe::IsValidSwTraceString<arm::pipe::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  fmt::format("Trying to register a counter set already registered (\"{}\")",
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  fmt::format("Trying to connect a counter set (UID: {}) to an invalid "
146  "parent category (name: \"{}\")",
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  fmt::format("Trying to connect a counter set (UID: {}) to a parent category "
157  "that is not registered (name: \"{}\")",
158  counterSetUidPeek,
159  parentCategoryNameValue));
160  }
161  }
162 
163  // Get the counter set UID
164  uint16_t counterSetUid = GetNextUid();
165  ARMNN_ASSERT(counterSetUid == counterSetUidPeek);
166 
167  // Create the counter set
168  CounterSetPtr counterSet = std::make_unique<CounterSet>(counterSetUid, counterSetName, count);
169  ARMNN_ASSERT(counterSet);
170 
171  // Get the raw counter set pointer
172  const CounterSet* counterSetPtr = counterSet.get();
173  ARMNN_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  !arm::pipe::IsValidSwTraceString<arm::pipe::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  !arm::pipe::IsValidSwTraceString<arm::pipe::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  !arm::pipe::IsValidSwTraceString<arm::pipe::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  && !arm::pipe::IsValidSwTraceString<arm::pipe::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  fmt::format("Trying to connect a counter to a category that is not registered (name: \"{}\")",
248  parentCategoryName));
249  }
250 
251  // Get the parent category
252  const CategoryPtr& parentCategory = *categoryIt;
253  ARMNN_ASSERT(parentCategory);
254 
255  // Check that a counter with the given name is not already registered within the parent category
256  const std::vector<uint16_t>& parentCategoryCounters = parentCategory->m_Counters;
257  for (uint16_t parentCategoryCounterUid : parentCategoryCounters)
258  {
259  const Counter* parentCategoryCounter = GetCounter(parentCategoryCounterUid);
260  ARMNN_ASSERT(parentCategoryCounter);
261 
262  if (parentCategoryCounter->m_Name == name)
263  {
265  fmt::format("Trying to register a counter to category \"{}\" with a name that "
266  "is already used within that category (name: \"{}\")",
267  parentCategoryName,
268  name));
269  }
270  }
271 
272  // Check that a counter set with the given (optional) UID is already registered
273  uint16_t counterSetUidValue = counterSetUid.has_value() ? counterSetUid.value() : 0;
274  if (counterSetUidValue > 0)
275  {
276  // Check that the (optional) counter set is already registered
277  if (!IsCounterSetRegistered(counterSetUidValue))
278  {
280  fmt::format("Trying to connect a counter to a counter set that is "
281  "not registered (counter set UID: {})",
282  counterSetUidValue));
283  }
284  }
285 
286  // Get the number of cores (this call may throw)
287  uint16_t deviceUidValue = deviceUid.has_value() ? deviceUid.value() : 0;
288  uint16_t deviceCores = GetNumberOfCores(numberOfCores, deviceUidValue);
289 
290  // Get the counter UIDs and calculate the max counter UID
291  std::vector<uint16_t> counterUids = GetNextCounterUids(uid, deviceCores);
292  ARMNN_ASSERT(!counterUids.empty());
293  uint16_t maxCounterUid = deviceCores <= 1 ? counterUids.front() : counterUids.back();
294 
295  // Get the counter units
296  const std::string unitsValue = units.has_value() ? units.value() : "";
297 
298  // Create the counter
299  CounterPtr counter = std::make_shared<Counter>(armnn::profiling::BACKEND_ID,
300  counterUids.front(),
301  maxCounterUid,
302  counterClass,
303  interpolation,
304  multiplier,
305  name,
306  description,
307  unitsValue,
308  deviceUidValue,
309  counterSetUidValue);
310  ARMNN_ASSERT(counter);
311 
312  // Get the raw counter pointer
313  const Counter* counterPtr = counter.get();
314  ARMNN_ASSERT(counterPtr);
315 
316  // Process multiple counters if necessary
317  for (uint16_t counterUid : counterUids)
318  {
319  // Connect the counter to the parent category
320  parentCategory->m_Counters.push_back(counterUid);
321 
322  // Register the counter
323  m_Counters.insert(std::make_pair(counterUid, counter));
324  }
325 
326  return counterPtr;
327 }
328 
329 const Category* CounterDirectory::GetCategory(const std::string& categoryName) const
330 {
331  auto it = FindCategory(categoryName);
332  if (it == m_Categories.end())
333  {
334  return nullptr;
335  }
336 
337  const Category* category = it->get();
338  ARMNN_ASSERT(category);
339 
340  return category;
341 }
342 
343 const Device* CounterDirectory::GetDevice(uint16_t deviceUid) const
344 {
345  auto it = FindDevice(deviceUid);
346  if (it == m_Devices.end())
347  {
348  return nullptr;
349  }
350 
351  const Device* device = it->second.get();
352  ARMNN_ASSERT(device);
353  ARMNN_ASSERT(device->m_Uid == deviceUid);
354 
355  return device;
356 }
357 
358 const CounterSet* CounterDirectory::GetCounterSet(uint16_t counterSetUid) const
359 {
360  auto it = FindCounterSet(counterSetUid);
361  if (it == m_CounterSets.end())
362  {
363  return nullptr;
364  }
365 
366  const CounterSet* counterSet = it->second.get();
367  ARMNN_ASSERT(counterSet);
368  ARMNN_ASSERT(counterSet->m_Uid == counterSetUid);
369 
370  return counterSet;
371 }
372 
373 const Counter* CounterDirectory::GetCounter(uint16_t counterUid) const
374 {
375  auto it = FindCounter(counterUid);
376  if (it == m_Counters.end())
377  {
378  return nullptr;
379  }
380 
381  const Counter* counter = it->second.get();
382  ARMNN_ASSERT(counter);
383  ARMNN_ASSERT(counter->m_Uid <= counterUid);
384  ARMNN_ASSERT(counter->m_Uid <= counter->m_MaxCounterUid);
385 
386  return counter;
387 }
388 
389 bool CounterDirectory::IsCategoryRegistered(const std::string& categoryName) const
390 {
391  auto it = FindCategory(categoryName);
392 
393  return it != m_Categories.end();
394 }
395 
396 bool CounterDirectory::IsDeviceRegistered(uint16_t deviceUid) const
397 {
398  auto it = FindDevice(deviceUid);
399 
400  return it != m_Devices.end();
401 }
402 
403 bool CounterDirectory::IsDeviceRegistered(const std::string& deviceName) const
404 {
405  auto it = FindDevice(deviceName);
406 
407  return it != m_Devices.end();
408 }
409 
410 bool CounterDirectory::IsCounterSetRegistered(uint16_t counterSetUid) const
411 {
412  auto it = FindCounterSet(counterSetUid);
413 
414  return it != m_CounterSets.end();
415 }
416 
417 bool CounterDirectory::IsCounterSetRegistered(const std::string& counterSetName) const
418 {
419  auto it = FindCounterSet(counterSetName);
420 
421  return it != m_CounterSets.end();
422 }
423 
424 bool CounterDirectory::IsCounterRegistered(uint16_t counterUid) const
425 {
426  auto it = FindCounter(counterUid);
427 
428  return it != m_Counters.end();
429 }
430 
431 bool CounterDirectory::IsCounterRegistered(const std::string& counterName) const
432 {
433  auto it = FindCounter(counterName);
434 
435  return it != m_Counters.end();
436 }
437 
439 {
440  // Clear all the counter directory contents
441  m_Categories.clear();
442  m_Devices.clear();
443  m_CounterSets.clear();
444  m_Counters.clear();
445 }
446 
447 CategoriesIt CounterDirectory::FindCategory(const std::string& categoryName) const
448 {
449  return std::find_if(m_Categories.begin(), m_Categories.end(), [&categoryName](const CategoryPtr& category)
450  {
451  ARMNN_ASSERT(category);
452 
453  return category->m_Name == categoryName;
454  });
455 }
456 
457 DevicesIt CounterDirectory::FindDevice(uint16_t deviceUid) const
458 {
459  return m_Devices.find(deviceUid);
460 }
461 
462 DevicesIt CounterDirectory::FindDevice(const std::string& deviceName) const
463 {
464  return std::find_if(m_Devices.begin(), m_Devices.end(), [&deviceName](const auto& pair)
465  {
466  ARMNN_ASSERT(pair.second);
467  ARMNN_ASSERT(pair.second->m_Uid == pair.first);
468 
469  return pair.second->m_Name == deviceName;
470  });
471 }
472 
473 CounterSetsIt CounterDirectory::FindCounterSet(uint16_t counterSetUid) const
474 {
475  return m_CounterSets.find(counterSetUid);
476 }
477 
478 CounterSetsIt CounterDirectory::FindCounterSet(const std::string& counterSetName) const
479 {
480  return std::find_if(m_CounterSets.begin(), m_CounterSets.end(), [&counterSetName](const auto& pair)
481  {
482  ARMNN_ASSERT(pair.second);
483  ARMNN_ASSERT(pair.second->m_Uid == pair.first);
484 
485  return pair.second->m_Name == counterSetName;
486  });
487 }
488 
489 CountersIt CounterDirectory::FindCounter(uint16_t counterUid) const
490 {
491  return m_Counters.find(counterUid);
492 }
493 
494 CountersIt CounterDirectory::FindCounter(const std::string& counterName) const
495 {
496  return std::find_if(m_Counters.begin(), m_Counters.end(), [&counterName](const auto& pair)
497  {
498  ARMNN_ASSERT(pair.second);
499  ARMNN_ASSERT(pair.first >= pair.second->m_Uid && pair.first <= pair.second->m_MaxCounterUid);
500 
501  return pair.second->m_Name == counterName;
502  });
503 }
504 
505 uint16_t CounterDirectory::GetNumberOfCores(const Optional<uint16_t>& numberOfCores,
506  uint16_t deviceUid)
507 {
508  // To get the number of cores, apply the following rules:
509  //
510  // 1. If numberOfCores is set then take it as the deviceCores value
511  // 2. If numberOfCores is not set then check to see if this counter is directly associated with a device,
512  // if so then that devices number of cores is taken as the deviceCores value
513  // 3. If none of the above holds then set deviceCores to zero
514 
515  // 1. If numberOfCores is set then take it as the deviceCores value
516  if (numberOfCores.has_value())
517  {
518  // Get the number of cores
519  return numberOfCores.value();
520  }
521 
522  // 2. If numberOfCores is not set then check to see if this counter is directly associated with a device,
523  // if so then that devices number of cores is taken as the deviceCores value
524  if (deviceUid > 0)
525  {
526  // Check that the (optional) device is already registered
527  auto deviceIt = FindDevice(deviceUid);
528  if (deviceIt == m_Devices.end())
529  {
531  fmt::format("Trying to connect a counter to a device that is not registered (device UID {})",
532  deviceUid));
533  }
534 
535  // Get the associated device
536  const DevicePtr& device = deviceIt->second;
537  ARMNN_ASSERT(device);
538 
539  // Get the number of cores of the associated device
540  return device->m_Cores;
541  }
542 
543  // 3. If none of the above holds then set deviceCores to zero
544  return 0;
545 }
546 
547 } // namespace profiling
548 
549 } // 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