From 6db5f20ade72896ebf0f6513a4832b8f2e917aa0 Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Thu, 5 Sep 2019 12:02:04 +0100 Subject: IVGCVSW-3691 Rework the CounterDirectory class to take into consideration the connections between components * Added constructors and connections to the profiling classes * Used hash table to keep track of the profiling objects by UID * Added register methods * Added find/check helper methods * Updated the makefile to include the profiling directory * Added unit tests for the CounterDirectory class * Added ICounterDirectory interface class for read-only use * Added custom macro to locally disable conversion warnings Change-Id: I3f53a68663ee77b8d03ac0ef7dc01e90c6893511 Signed-off-by: Matteo Martincigh --- CMakeLists.txt | 30 +- include/armnn/Conversion.hpp | 40 ++ src/profiling/CounterDirectory.cpp | 629 ++++++++++++++--- src/profiling/CounterDirectory.hpp | 155 ++--- src/profiling/ICounterDirectory.hpp | 164 +++++ src/profiling/ProfilingUtils.cpp | 73 +- src/profiling/ProfilingUtils.hpp | 66 +- src/profiling/test/ProfilingTests.cpp | 942 +++++++++++++++++++++++++- src/profiling/test/SendCounterPacketTests.cpp | 9 +- 9 files changed, 1881 insertions(+), 227 deletions(-) create mode 100644 include/armnn/Conversion.hpp create mode 100644 src/profiling/ICounterDirectory.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a04f30baf2..0c66eef9d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,10 @@ endif() list(APPEND armnn_sources include/armnn/ArmNN.hpp + include/armnn/BackendHelper.hpp include/armnn/BackendId.hpp + include/armnn/Conversion.hpp + include/armnn/Deprecated.hpp include/armnn/Descriptors.hpp include/armnn/DescriptorsFwd.hpp include/armnn/Exceptions.hpp @@ -428,28 +431,29 @@ list(APPEND armnn_sources src/profiling/EncodeVersion.hpp src/profiling/Holder.cpp src/profiling/Holder.hpp + src/profiling/IBufferWrapper.hpp + src/profiling/ICounterDirectory.hpp + src/profiling/ISendCounterPacket.hpp + src/profiling/IPeriodicCounterCapture.hpp src/profiling/IProfilingConnection.hpp src/profiling/Packet.cpp src/profiling/Packet.hpp src/profiling/PacketVersionResolver.cpp src/profiling/PacketVersionResolver.hpp + src/profiling/PeriodicCounterSelectionCommandHandler.cpp + src/profiling/PeriodicCounterSelectionCommandHandler.hpp src/profiling/ProfilingConnectionFactory.cpp src/profiling/ProfilingConnectionFactory.hpp - src/profiling/IBufferWrapper.hpp - src/profiling/IPeriodicCounterCapture.hpp - src/profiling/ISendCounterPacket.hpp - src/profiling/SendCounterPacket.hpp + src/profiling/ProfilingService.cpp + src/profiling/ProfilingService.hpp + src/profiling/ProfilingStateMachine.cpp + src/profiling/ProfilingStateMachine.hpp + src/profiling/ProfilingUtils.cpp + src/profiling/ProfilingUtils.hpp src/profiling/SendCounterPacket.cpp + src/profiling/SendCounterPacket.hpp src/profiling/SocketProfilingConnection.cpp src/profiling/SocketProfilingConnection.hpp - src/profiling/ProfilingUtils.hpp - src/profiling/ProfilingUtils.cpp - src/profiling/ProfilingStateMachine.cpp - src/profiling/ProfilingStateMachine.hpp - src/profiling/ProfilingService.cpp - src/profiling/ProfilingService.hpp - src/profiling/PeriodicCounterSelectionCommandHandler.cpp - src/profiling/PeriodicCounterSelectionCommandHandler.hpp third-party/half/half.hpp ) @@ -473,6 +477,7 @@ add_library_ex(armnn SHARED ${armnn_sources}) target_include_directories(armnn PRIVATE src/armnn) target_include_directories(armnn PRIVATE src/armnnUtils) target_include_directories(armnn PRIVATE src/backends) +target_include_directories(armnn PRIVATE src/profiling) target_link_libraries(armnn armnnUtils) @@ -745,6 +750,7 @@ if(BUILD_UNIT_TESTS) target_include_directories(UnitTests PRIVATE src/armnn) target_include_directories(UnitTests PRIVATE src/armnnUtils) target_include_directories(UnitTests PRIVATE src/backends) + target_include_directories(UnitTests PRIVATE src/profiling) if(VALGRIND_FOUND) if(HEAP_PROFILING OR LEAK_CHECKING) diff --git a/include/armnn/Conversion.hpp b/include/armnn/Conversion.hpp new file mode 100644 index 0000000000..37338eded7 --- /dev/null +++ b/include/armnn/Conversion.hpp @@ -0,0 +1,40 @@ +// +// Copyright © 2019 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#if __GNUC__ +# define ARMNN_NO_CONVERSION_WARN_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wconversion\"") + +# define ARMNN_NO_CONVERSION_WARN_END \ + _Pragma("GCC diagnostic pop") + +#elif __clang__ +# define ARMNN_NO_CONVERSION_WARN_BEGIN \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wconversion\"") + +# define ARMNN_NO_CONVERSION_WARN_END \ + _Pragma("clang diagnostic pop") + +#elif defined (_MSC_VER) +# define ARMNN_NO_CONVERSION_WARN_BEGIN \ + __pragma(warning( push )) \ + __pragma(warning(disable : 4101)) + +# define ARMNN_NO_CONVERSION_WARN_END \ + __pragma(warning( pop )) + +#else +# define ARMNN_NO_CONVERSION_WARN_BEGIN +# define ARMNN_NO_CONVERSION_WARN_END +#endif + +#define ARMNN_SUPRESS_CONVERSION_WARNING(func) \ +ARMNN_NO_CONVERSION_WARN_BEGIN \ +func; \ +ARMNN_NO_CONVERSION_WARN_END diff --git a/src/profiling/CounterDirectory.cpp b/src/profiling/CounterDirectory.cpp index a84897995d..cef3d6a76d 100644 --- a/src/profiling/CounterDirectory.cpp +++ b/src/profiling/CounterDirectory.cpp @@ -4,8 +4,12 @@ // #include "CounterDirectory.hpp" +#include "ProfilingUtils.hpp" #include +#include + +#include namespace armnn { @@ -13,149 +17,616 @@ namespace armnn namespace profiling { -CounterDirectory::CounterDirectory(uint16_t uid, - const std::string& name, - uint16_t deviceCount, - uint16_t counterCount, - uint16_t categoryCount) - : m_Uid(uid) - , m_Name(name) - , m_DeviceCount(deviceCount) - , m_CounterCount(counterCount) - , m_CategoryCount(categoryCount) - , m_DeviceIds(deviceCount) - , m_CounterIds(counterCount) - , m_CategoryIds(categoryCount) - , m_DeviceObjects(deviceCount) - , m_CounterObjects(counterCount) - , m_CategoryObjects(categoryCount) -{} - -// Helper methods -void CounterDirectory::CheckDeviceIndex(uint16_t index) const +const Category* CounterDirectory::RegisterCategory(const std::string& categoryName, + const Optional& deviceUid, + const Optional& counterSetUid) { - if (index >= m_DeviceCount) + // Check that the given category name is valid + if (categoryName.empty() || + !IsValidSwTraceString(categoryName)) + { + throw InvalidArgumentException("Trying to register a category with an invalid name"); + } + + // Check that the given category is not already registered + if (CheckIfCategoryIsRegistered(categoryName)) { - throw InvalidArgumentException("Invalid device index"); + throw InvalidArgumentException( + boost::str(boost::format("Trying to register a category already registered (\"%1%\")") + % categoryName)); } + + // Check that a device with the given (optional) UID is already registered + uint16_t deviceUidValue = deviceUid.has_value() ? deviceUid.value() : 0; + if (deviceUidValue > 0) + { + // Check that the (optional) device is already registered + if (!CheckIfDeviceIsRegistered(deviceUidValue)) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a category (\"%1%\") to a device that is " + "not registered (UID %2%)") + % categoryName + % deviceUidValue)); + } + } + + // Check that a counter set with the given (optional) UID is already registered + uint16_t counterSetUidValue = counterSetUid.has_value() ? counterSetUid.value() : 0; + if (counterSetUidValue > 0) + { + // Check that the (optional) counter set is already registered + if (!CheckIfCounterSetIsRegistered(counterSetUidValue)) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a category (name: \"%1%\") to a counter set " + "that is not registered (UID: %2%)") + % categoryName + % counterSetUidValue)); + } + } + + // Create the category + CategoryPtr category = std::make_unique(categoryName, deviceUidValue, counterSetUidValue); + BOOST_ASSERT(category); + + // Get the raw category pointer + const Category* categoryPtr = category.get(); + BOOST_ASSERT(categoryPtr); + + // Register the category + m_Categories.insert(std::move(category)); + + return categoryPtr; } -void CounterDirectory::CheckCounterIndex(uint16_t index) const +const Device* CounterDirectory::RegisterDevice(const std::string& deviceName, + uint16_t cores, + const Optional& parentCategoryName) { - if (index >= m_CounterCount) + // Check that the given device name is valid + if (deviceName.empty() || + !IsValidSwTraceString(deviceName)) + { + throw InvalidArgumentException("Trying to register a device with an invalid name"); + } + + // Check that a device with the given name is not already registered + if (CheckIfDeviceIsRegistered(deviceName)) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to register a device already registered (\"%1%\")") + % deviceName)); + } + + // 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 + // the registration fails. We'll get a proper one once we're sure that the device can be registered + uint16_t deviceUidPeek = GetNextUid(true); + + // Check that a category with the given (optional) parent category name is already registered + Category* parentCategoryPtr = nullptr; + if (parentCategoryName.has_value()) { - throw InvalidArgumentException("Invalid counter index"); + // Get the (optional) parent category name + const std::string& parentCategoryNameValue = parentCategoryName.value(); + if (parentCategoryNameValue.empty()) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a device (name: \"%1%\") to an invalid " + "parent category (name: \"%2%\")") + % deviceName + % parentCategoryNameValue)); + } + + // Check that the given parent category is already registered + auto categoryIt = FindCategory(parentCategoryNameValue); + if (categoryIt == m_Categories.end()) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a device (name: \"%1%\") to a parent category that " + "is not registered (name: \"%2%\")") + % deviceName + % parentCategoryNameValue)); + } + + // Get the parent category + const CategoryPtr& parentCategory = *categoryIt; + BOOST_ASSERT(parentCategory); + + // Check that the given parent category is not already connected to another device + if (parentCategory->m_DeviceUid != 0 && parentCategory->m_DeviceUid != deviceUidPeek) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a device (UID: %1%) to a parent category that is " + "already connected to a different device " + "(category \"%2%\" connected to device %3%)") + % deviceUidPeek + % parentCategoryNameValue + % parentCategory->m_DeviceUid)); + } + + // The parent category can be associated to the device that is about to be registered. + // Get the raw pointer to the parent category (to be used later when the device is actually been + // registered, to make sure that the category is associated to an existing device) + parentCategoryPtr = parentCategory.get(); } + + // Get the device UID + uint16_t deviceUid = GetNextUid(); + BOOST_ASSERT(deviceUid == deviceUidPeek); + + // Create the device + DevicePtr device = std::make_unique(deviceUid, deviceName, cores); + BOOST_ASSERT(device); + + // Get the raw device pointer + const Device* devicePtr = device.get(); + BOOST_ASSERT(devicePtr); + + // Register the device + m_Devices.insert(std::make_pair(deviceUid, std::move(device))); + + // Connect the device to the parent category, if required + if (parentCategoryPtr) + { + // Set the device UID in the parent category + parentCategoryPtr->m_DeviceUid = deviceUid; + } + + return devicePtr; } -void CounterDirectory::CheckCategoryIndex(uint16_t index) const +const CounterSet* CounterDirectory::RegisterCounterSet(const std::string& counterSetName, + uint16_t count, + const Optional& parentCategoryName) { - if (index >= m_CategoryCount) + // Check that the given counter set name is valid + if (counterSetName.empty() || + !IsValidSwTraceString(counterSetName)) { - throw InvalidArgumentException("Invalid category index"); + throw InvalidArgumentException("Trying to register a counter set with an invalid name"); } + + // Check that a counter set with the given name is not already registered + if (CheckIfCounterSetIsRegistered(counterSetName)) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to register a counter set already registered (\"%1%\")") + % counterSetName)); + } + + // 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 + // the registration fails. We'll get a proper one once we're sure that the counter set can be registered + uint16_t counterSetUidPeek = GetNextUid(true); + + // Check that a category with the given (optional) parent category name is already registered + Category* parentCategoryPtr = nullptr; + if (parentCategoryName.has_value()) + { + // Get the (optional) parent category name + const std::string& parentCategoryNameValue = parentCategoryName.value(); + if (parentCategoryNameValue.empty()) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a counter set (UID: %1%) to an invalid " + "parent category (name: \"%2%\")") + % counterSetUidPeek + % parentCategoryNameValue)); + } + + // Check that the given parent category is already registered + auto it = FindCategory(parentCategoryNameValue); + if (it == m_Categories.end()) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a counter set (UID: %1%) to a parent category " + "that is not registered (name: \"%2%\")") + % counterSetUidPeek + % parentCategoryNameValue)); + } + + // Get the parent category + const CategoryPtr& parentCategory = *it; + BOOST_ASSERT(parentCategory); + + // Check that the given parent category is not already connected to another counter set + if (parentCategory->m_CounterSetUid != 0 && parentCategory->m_CounterSetUid != counterSetUidPeek) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a counter set (UID: %1%) to a parent category " + "that is already connected to a different counter set " + "(category \"%2%\" connected to counter set %3%)") + % counterSetUidPeek + % parentCategoryNameValue + % parentCategory->m_CounterSetUid)); + } + + // The parent category can be associated to the counter set that is about to be registered. + // Get the raw pointer to the parent category (to be used later when the counter set is actually been + // registered, to make sure that the category is associated to an existing counter set) + parentCategoryPtr = parentCategory.get(); + } + + // Get the counter set UID + uint16_t counterSetUid = GetNextUid(); + BOOST_ASSERT(counterSetUid == counterSetUidPeek); + + // Create the counter set + CounterSetPtr counterSet = std::make_unique(counterSetUid, counterSetName, count); + BOOST_ASSERT(counterSet); + + // Get the raw counter set pointer + const CounterSet* counterSetPtr = counterSet.get(); + BOOST_ASSERT(counterSetPtr); + + // Register the counter set + m_CounterSets.insert(std::make_pair(counterSetUid, std::move(counterSet))); + + // Connect the counter set to the parent category, if required + if (parentCategoryPtr) + { + // Set the counter set UID in the parent category + parentCategoryPtr->m_CounterSetUid = counterSetUid; + } + + return counterSetPtr; } -// Getters for basic attributes -uint16_t CounterDirectory::GetUid() const +const Counter* CounterDirectory::RegisterCounter(const std::string& parentCategoryName, + uint16_t counterClass, + uint16_t interpolation, + double multiplier, + const std::string& name, + const std::string& description, + const Optional& units, + const Optional& numberOfCores, + const Optional& deviceUid, + const Optional& counterSetUid) { - return m_Uid; + // Check that the given parent category name is valid + if (parentCategoryName.empty() || + !IsValidSwTraceString(parentCategoryName)) + { + throw InvalidArgumentException("Trying to register a counter with an invalid parent category name"); + } + + // Check that the given class is valid + if (counterClass != 0 && counterClass != 1) + { + throw InvalidArgumentException("Trying to register a counter with an invalid class"); + } + + // Check that the given interpolation is valid + if (interpolation != 0 && interpolation != 1) + { + throw InvalidArgumentException("Trying to register a counter with an invalid interpolation"); + } + + // Check that the given multiplier is valid + if (multiplier == .0f) + { + throw InvalidArgumentException("Trying to register a counter with an invalid multiplier"); + } + + // Check that the given name is valid + if (name.empty() || + !IsValidSwTraceString(name)) + { + throw InvalidArgumentException("Trying to register a counter with an invalid name"); + } + + // Check that the given description is valid + if (description.empty() || + !IsValidSwTraceString(description)) + { + throw InvalidArgumentException("Trying to register a counter with an invalid description"); + } + + // Check that the given units are valid + if (units.has_value() + && !IsValidSwTraceString(units.value())) + { + throw InvalidArgumentException("Trying to register a counter with a invalid units"); + } + + // Check that the given parent category is registered + auto categoryIt = FindCategory(parentCategoryName); + if (categoryIt == m_Categories.end()) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a counter to a category " + "that is not registered (name: \"%1%\")") + % parentCategoryName)); + } + + // Get the parent category + const CategoryPtr& parentCategory = *categoryIt; + BOOST_ASSERT(parentCategory); + + // Check that a counter with the given name is not already registered within the parent category + const std::vector& parentCategoryCounters = parentCategory->m_Counters; + for (uint16_t parentCategoryCounterUid : parentCategoryCounters) + { + const Counter* parentCategoryCounter = GetCounter(parentCategoryCounterUid); + BOOST_ASSERT(parentCategoryCounter); + + if (parentCategoryCounter->m_Name == name) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to register a counter to category \"%1%\" with a name that " + "is already used within that category (name: \"%2%\")") + % parentCategoryName + % name)); + } + } + + // Check that a counter set with the given (optional) UID is already registered + uint16_t counterSetUidValue = counterSetUid.has_value() ? counterSetUid.value() : 0; + if (counterSetUidValue > 0) + { + // Check that the (optional) counter set is already registered + if (!CheckIfCounterSetIsRegistered(counterSetUidValue)) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a counter to a counter set that is " + "not registered (counter set UID: %1%)") + % counterSetUidValue)); + } + } + + // Get the number of cores (this call may throw) + uint16_t deviceUidValue = deviceUid.has_value() ? deviceUid.value() : 0; + uint16_t deviceCores = GetNumberOfCores(numberOfCores, deviceUidValue, parentCategory); + + // Get the counter UIDs and calculate the max counter UID + std::vector counterUids = GetNextCounterUids(deviceCores); + BOOST_ASSERT(!counterUids.empty()); + uint16_t maxCounterUid = deviceCores <= 1 ? counterUids.front() : counterUids.back(); + + // Get the counter units + const std::string unitsValue = units.has_value() ? units.value() : ""; + + // Create the counter + CounterPtr counter = std::make_shared(counterUids.front(), + maxCounterUid, + counterClass, + interpolation, + multiplier, + name, + description, + unitsValue, + deviceUidValue, + counterSetUidValue); + BOOST_ASSERT(counter); + + // Get the raw counter pointer + const Counter* counterPtr = counter.get(); + BOOST_ASSERT(counterPtr); + + // Process multiple counters if necessary + for (uint16_t counterUid : counterUids) + { + // Connect the counter to the parent category + parentCategory->m_Counters.push_back(counterUid); + + // Register the counter + m_Counters.insert(std::make_pair(counterUid, counter)); + } + + return counterPtr; } -const std::string& CounterDirectory::GetName() const +const Category* CounterDirectory::GetCategory(const std::string& categoryName) const { - return m_Name; + auto it = FindCategory(categoryName); + if (it == m_Categories.end()) + { + return nullptr; + } + + const Category* category = it->get(); + BOOST_ASSERT(category); + + return category; } -// Getters for counts -uint16_t CounterDirectory::GetDeviceCount() const +const Device* CounterDirectory::GetDevice(uint16_t deviceUid) const { - return m_DeviceCount; + auto it = FindDevice(deviceUid); + if (it == m_Devices.end()) + { + return nullptr; + } + + const Device* device = it->second.get(); + BOOST_ASSERT(device); + BOOST_ASSERT(device->m_Uid == deviceUid); + + return device; } -uint16_t CounterDirectory::GetCounterCount() const +const CounterSet* CounterDirectory::GetCounterSet(uint16_t counterSetUid) const { - return m_CounterCount; + auto it = FindCounterSet(counterSetUid); + if (it == m_CounterSets.end()) + { + return nullptr; + } + + const CounterSet* counterSet = it->second.get(); + BOOST_ASSERT(counterSet); + BOOST_ASSERT(counterSet->m_Uid == counterSetUid); + + return counterSet; } -uint16_t CounterDirectory::GetCategoryCount() const +const Counter* CounterDirectory::GetCounter(uint16_t counterUid) const { - return m_CategoryCount; + auto it = FindCounter(counterUid); + if (it == m_Counters.end()) + { + return nullptr; + } + + const Counter* counter = it->second.get(); + BOOST_ASSERT(counter); + BOOST_ASSERT(counter->m_Uid <= counterUid); + BOOST_ASSERT(counter->m_Uid <= counter->m_MaxCounterUid); + + return counter; } -// Getters and setters for devices -void CounterDirectory::GetDeviceValue(uint16_t index, uint32_t& value) const +CategoriesIt CounterDirectory::FindCategory(const std::string& categoryName) const { - CheckDeviceIndex(index); - value = m_DeviceIds[index].load(); + return std::find_if(m_Categories.begin(), m_Categories.end(), [&categoryName](const CategoryPtr& category) + { + BOOST_ASSERT(category); + + return category->m_Name == categoryName; + }); } -void CounterDirectory::SetDeviceValue(uint16_t index, uint32_t value) +DevicesIt CounterDirectory::FindDevice(uint16_t deviceUid) const { - CheckDeviceIndex(index); - m_DeviceIds[index].store(value); + return m_Devices.find(deviceUid); } -void CounterDirectory::GetDeviceObject(uint16_t index, Device* device) const +DevicesIt CounterDirectory::FindDevice(const std::string& deviceName) const { - CheckDeviceIndex(index); - device = m_DeviceObjects[index].load(); + return std::find_if(m_Devices.begin(), m_Devices.end(), [&deviceName](const auto& pair) + { + BOOST_ASSERT(pair.second); + BOOST_ASSERT(pair.second->m_Uid == pair.first); + + return pair.second->m_Name == deviceName; + }); } -void CounterDirectory::SetDeviceObject(uint16_t index, Device* device) +CounterSetsIt CounterDirectory::FindCounterSet(uint16_t counterSetUid) const { - CheckDeviceIndex(index); - m_DeviceObjects[index].store(device); + return m_CounterSets.find(counterSetUid); } -// Getters and setters for counters -void CounterDirectory::GetCounterValue(uint16_t index, uint32_t& value) const +CounterSetsIt CounterDirectory::FindCounterSet(const std::string& counterSetName) const { - CheckCounterIndex(index); - value = m_CounterIds[index].load(); + return std::find_if(m_CounterSets.begin(), m_CounterSets.end(), [&counterSetName](const auto& pair) + { + BOOST_ASSERT(pair.second); + BOOST_ASSERT(pair.second->m_Uid == pair.first); + + return pair.second->m_Name == counterSetName; + }); } -void CounterDirectory::SetCounterValue(uint16_t index, uint32_t value) +CountersIt CounterDirectory::FindCounter(uint16_t counterUid) const { - CheckCounterIndex(index); - m_CounterIds[index].store(value); + return m_Counters.find(counterUid); } -void CounterDirectory::GetCounterObject(uint16_t index, Counter* counter) const +bool CounterDirectory::CheckIfCategoryIsRegistered(const std::string& categoryName) const { - CheckCounterIndex(index); - counter = m_CounterObjects[index].load(); + auto it = FindCategory(categoryName); + + return it != m_Categories.end(); } -void CounterDirectory::SetCounterObject(uint16_t index, Counter* counter) +bool CounterDirectory::CheckIfDeviceIsRegistered(uint16_t deviceUid) const { - CheckCounterIndex(index); - m_CounterObjects[index].store(counter); + auto it = FindDevice(deviceUid); + + return it != m_Devices.end(); } -// Getters and setters for categories -void CounterDirectory::GetCategoryValue(uint16_t index, uint32_t& value) const +bool CounterDirectory::CheckIfDeviceIsRegistered(const std::string& deviceName) const { - CheckCategoryIndex(index); - value = m_CategoryIds[index].load(); + auto it = FindDevice(deviceName); + + return it != m_Devices.end(); } -void CounterDirectory::SetCategoryValue(uint16_t index, uint32_t value) +bool CounterDirectory::CheckIfCounterSetIsRegistered(uint16_t counterSetUid) const { - CheckCategoryIndex(index); - m_CategoryIds[index].store(value); + auto it = FindCounterSet(counterSetUid); + + return it != m_CounterSets.end(); } -void CounterDirectory::GetCategoryObject(uint16_t index, Category* category) const +bool CounterDirectory::CheckIfCounterSetIsRegistered(const std::string& counterSetName) const { - CheckCategoryIndex(index); - category = m_CategoryObjects[index].load(); + auto it = FindCounterSet(counterSetName); + + return it != m_CounterSets.end(); } -void CounterDirectory::SetCategoryObject(uint16_t index, Category* category) +uint16_t CounterDirectory::GetNumberOfCores(const Optional& numberOfCores, + uint16_t deviceUid, + const CategoryPtr& parentCategory) { - CheckCategoryIndex(index); - m_CategoryObjects[index].store(category); + BOOST_ASSERT(parentCategory); + + // To get the number of cores, apply the following rules: + // + // 1. If numberOfCores is set then take it as the deviceCores value + // 2. If numberOfCores is not set then check to see if this counter is directly associated with a device, + // if so then that devices number of cores is taken as the deviceCores value + // 3. If neither of the above is set then look at the category to see if it has a device associated with it, + // if it does then take that device's numberOfCores as the deviceCores value + // 4. If none of the above holds then set deviceCores to zero + + // 1. If numberOfCores is set then take it as the deviceCores value + if (numberOfCores.has_value()) + { + // Get the number of cores + return numberOfCores.value(); + } + + // 2. If numberOfCores is not set then check to see if this counter is directly associated with a device, + // if so then that devices number of cores is taken as the deviceCores value + if (deviceUid > 0) + { + // Check that the (optional) device is already registered + auto deviceIt = FindDevice(deviceUid); + if (deviceIt == m_Devices.end()) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to connect a counter to a device that is " + "not registered (device UID %1%)") + % deviceUid)); + } + + // Get the associated device + const DevicePtr& device = deviceIt->second; + BOOST_ASSERT(device); + + // Get the number of cores of the associated device + return device->m_Cores; + } + + // 3. If neither of the above is set then look at the category to see if it has a device associated with it, + // if it does then take that device's numberOfCores as the deviceCores value + uint16_t parentCategoryDeviceUid = parentCategory->m_DeviceUid; + if (parentCategoryDeviceUid > 0) + { + // Check that the device associated to the parent category is already registered + auto deviceIt = FindDevice(parentCategoryDeviceUid); + if (deviceIt == m_Devices.end()) + { + throw InvalidArgumentException( + boost::str(boost::format("Trying to get the number of cores from a device that is " + "not registered (device UID %1%)") + % parentCategoryDeviceUid)); + } + + // Get the associated device + const DevicePtr& device = deviceIt->second; + BOOST_ASSERT(device); + + // Get the number of cores of the device associated to the parent category + return device->m_Cores; + } + + // 4. If none of the above holds then set deviceCores to zero + return 0; } } // namespace profiling diff --git a/src/profiling/CounterDirectory.hpp b/src/profiling/CounterDirectory.hpp index ec1ac273bc..a756a9a7bd 100644 --- a/src/profiling/CounterDirectory.hpp +++ b/src/profiling/CounterDirectory.hpp @@ -5,106 +5,89 @@ #pragma once -#include -#include -#include - -namespace armnn -{ +#include "ICounterDirectory.hpp" -namespace profiling -{ +#include -class Category -{ -public: - std::string m_Name; -}; +#include +#include +#include -class Device -{ -public: - uint16_t m_Uid; - std::string m_Name; - uint16_t m_Cores; -}; +#include -class Counter +namespace armnn { -public: - uint16_t m_Uid; - uint16_t m_MaxCounterUid; - uint16_t m_Class; - uint16_t m_Interpolation; - float m_Multiplier; - std::string m_Name; - std::string m_Description; - std::string m_Units; -}; -class CounterSet +namespace profiling { -public: - uint16_t m_Uid; - std::string m_Name; - uint16_t m_Count; -}; -class CounterDirectory final +class CounterDirectory final : public ICounterDirectory { public: - CounterDirectory(uint16_t uid, - const std::string& name, - uint16_t deviceCount, - uint16_t counterCount, - uint16_t categoryCount); - + CounterDirectory() = default; ~CounterDirectory() = default; - uint16_t GetUid() const; - const std::string& GetName() const; - - uint16_t GetDeviceCount() const; - uint16_t GetCounterCount() const; - uint16_t GetCategoryCount() const; - - void GetDeviceValue(uint16_t index, uint32_t& value) const; - void SetDeviceValue(uint16_t index, uint32_t value); - - void GetDeviceObject(uint16_t index, Device* counter) const; - void SetDeviceObject(uint16_t index, Device* counter); - - void GetCounterValue(uint16_t index, uint32_t& value) const; - void SetCounterValue(uint16_t index, uint32_t value); - - void GetCounterObject(uint16_t index, Counter* counter) const; - void SetCounterObject(uint16_t index, Counter* counter); - - void GetCategoryValue(uint16_t index, uint32_t& value) const; - void SetCategoryValue(uint16_t index, uint32_t value); - - void GetCategoryObject(uint16_t index, Category* counter) const; - void SetCategoryObject(uint16_t index, Category* counter); + // Register profiling objects + const Category* RegisterCategory (const std::string& categoryName, + const Optional& deviceUid = EmptyOptional(), + const Optional& counterSetUid = EmptyOptional()); + const Device* RegisterDevice (const std::string& deviceName, + uint16_t cores = 0, + const Optional& parentCategoryName = EmptyOptional()); + const CounterSet* RegisterCounterSet(const std::string& counterSetName, + uint16_t count = 0, + const Optional& parentCategoryName = EmptyOptional()); + const Counter* RegisterCounter (const std::string& parentCategoryName, + uint16_t counterClass, + uint16_t interpolation, + double multiplier, + const std::string& name, + const std::string& description, + const Optional& units = EmptyOptional(), + const Optional& numberOfCores = EmptyOptional(), + const Optional& deviceUid = EmptyOptional(), + const Optional& counterSetUid = EmptyOptional()); + + // Getters for counts + uint16_t GetCategoryCount() const override { return boost::numeric_cast(m_Categories.size()); } + uint16_t GetDeviceCount() const override { return boost::numeric_cast(m_Devices.size()); } + uint16_t GetCounterSetCount() const override { return boost::numeric_cast(m_CounterSets.size()); } + uint16_t GetCounterCount() const override { return boost::numeric_cast(m_Counters.size()); } + + // Getters for collections + const Categories& GetCategories() const override { return m_Categories; } + const Devices& GetDevices() const override { return m_Devices; } + const CounterSets& GetCounterSets() const override { return m_CounterSets; } + const Counters& GetCounters() const override { return m_Counters; } + + // Getters for profiling objects + const Category* GetCategory(const std::string& name) const override; + const Device* GetDevice(uint16_t uid) const override; + const CounterSet* GetCounterSet(uint16_t uid) const override; + const Counter* GetCounter(uint16_t uid) const override; private: - uint16_t m_Uid; - std::string m_Name; - - uint16_t m_DeviceCount; - uint16_t m_CounterCount; - uint16_t m_CategoryCount; - - std::vector> m_DeviceIds; - std::vector> m_CounterIds; - std::vector> m_CategoryIds; - - std::vector> m_DeviceObjects; - std::vector> m_CounterObjects; - std::vector> m_CategoryObjects; - - void CheckDeviceIndex(uint16_t index) const; - void CheckCounterIndex(uint16_t index) const; - void CheckCategoryIndex(uint16_t index) const; + // The profiling collections owned by the counter directory + Categories m_Categories; + Devices m_Devices; + CounterSets m_CounterSets; + Counters m_Counters; + + // Helper functions + CategoriesIt FindCategory(const std::string& categoryName) const; + DevicesIt FindDevice(uint16_t deviceUid) const; + DevicesIt FindDevice(const std::string& deviceName) const; + CounterSetsIt FindCounterSet(uint16_t counterSetUid) const; + CounterSetsIt FindCounterSet(const std::string& counterSetName) const; + CountersIt FindCounter(uint16_t counterUid) const; + bool CheckIfCategoryIsRegistered(const std::string& categoryName) const; + bool CheckIfDeviceIsRegistered(uint16_t deviceUid) const; + bool CheckIfDeviceIsRegistered(const std::string& deviceName) const; + bool CheckIfCounterSetIsRegistered(uint16_t counterSetUid) const; + bool CheckIfCounterSetIsRegistered(const std::string& counterSetName) const; + uint16_t GetNumberOfCores(const Optional& numberOfCores, + uint16_t deviceUid, + const CategoryPtr& parentCategory); }; } // namespace profiling diff --git a/src/profiling/ICounterDirectory.hpp b/src/profiling/ICounterDirectory.hpp new file mode 100644 index 0000000000..c7259ab041 --- /dev/null +++ b/src/profiling/ICounterDirectory.hpp @@ -0,0 +1,164 @@ +// +// Copyright © 2019 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace armnn +{ + +namespace profiling +{ + +// Forward declarations +class Category; +class Device; +class CounterSet; +class Counter; + +// Profiling objects smart pointer types +using CategoryPtr = std::unique_ptr; +using DevicePtr = std::unique_ptr; +using CounterSetPtr = std::unique_ptr; +using CounterPtr = std::shared_ptr; + +// Profiling objects collection types +using Categories = std::unordered_set; +using Devices = std::unordered_map; +using CounterSets = std::unordered_map; +using Counters = std::unordered_map; + +// Profiling objects collection iterator types +using CategoriesIt = Categories::const_iterator; +using DevicesIt = Devices::const_iterator; +using CounterSetsIt = CounterSets::const_iterator; +using CountersIt = Counters::const_iterator; + +class Category final +{ +public: + // Constructors + Category(const std::string& name, uint16_t deviceUid, uint16_t counterSetUid) + : m_Name(name) + , m_DeviceUid(deviceUid) + , m_CounterSetUid(counterSetUid) + {} + + // Fields + std::string m_Name; + + // Connections + std::vector m_Counters; // The UIDs of the counters associated with this category + uint16_t m_DeviceUid; // Optional, set to zero if the counter is not associated with a device + uint16_t m_CounterSetUid; // Optional, set to zero if the counter is not associated with a counter set +}; + +class Device final +{ +public: + // Constructors + Device(uint16_t deviceUid, const std::string& name, uint16_t cores) + : m_Uid(deviceUid) + , m_Name(name) + , m_Cores(cores) + {} + + // Fields + uint16_t m_Uid; + std::string m_Name; + uint16_t m_Cores; +}; + +class CounterSet final +{ +public: + // Constructors + CounterSet(uint16_t counterSetUid, const std::string& name, uint16_t count) + : m_Uid(counterSetUid) + , m_Name(name) + , m_Count(count) + {} + + // Fields + uint16_t m_Uid; + std::string m_Name; + uint16_t m_Count; +}; + +class Counter final +{ +public: + // Constructors + Counter(uint16_t counterUid, + uint16_t maxCounterUid, + uint16_t counterClass, + uint16_t interpolation, + double multiplier, + const std::string& name, + const std::string& description, + const std::string& units, + uint16_t deviceUid, + uint16_t counterSetUid) + : m_Uid(counterUid) + , m_MaxCounterUid(maxCounterUid) + , m_Class(counterClass) + , m_Interpolation(interpolation) + , m_Multiplier(multiplier) + , m_Name(name) + , m_Description(description) + , m_Units(units) + , m_DeviceUid(deviceUid) + , m_CounterSetUid(counterSetUid) + {} + + // Fields + uint16_t m_Uid; + uint16_t m_MaxCounterUid; + uint16_t m_Class; + uint16_t m_Interpolation; + double m_Multiplier; + std::string m_Name; + std::string m_Description; + std::string m_Units; // Optional, leave empty if the counter does not need units + + // Connections + uint16_t m_DeviceUid; // Optional, set to zero if the counter is not associated with a device + uint16_t m_CounterSetUid; // Optional, set to zero if the counter is not associated with a counter set +}; + +class ICounterDirectory +{ +public: + virtual ~ICounterDirectory() {} + + // Getters for counts + virtual uint16_t GetCategoryCount() const = 0; + virtual uint16_t GetDeviceCount() const = 0; + virtual uint16_t GetCounterSetCount() const = 0; + virtual uint16_t GetCounterCount() const = 0; + + // Getters for collections + virtual const Categories& GetCategories() const = 0; + virtual const Devices& GetDevices() const = 0; + virtual const CounterSets& GetCounterSets() const = 0; + virtual const Counters& GetCounters() const = 0; + + // Getters for profiling objects + virtual const Category* GetCategory(const std::string& name) const = 0; + virtual const Device* GetDevice(uint16_t uid) const = 0; + virtual const CounterSet* GetCounterSet(uint16_t uid) const = 0; + virtual const Counter* GetCounter(uint16_t uid) const = 0; +}; + +} // namespace profiling + +} // namespace armnn diff --git a/src/profiling/ProfilingUtils.cpp b/src/profiling/ProfilingUtils.cpp index ef67f0324c..e356ed739e 100644 --- a/src/profiling/ProfilingUtils.cpp +++ b/src/profiling/ProfilingUtils.cpp @@ -6,12 +6,12 @@ #include "ProfilingUtils.hpp" #include +#include #include #include #include -#include namespace armnn { @@ -19,25 +19,72 @@ namespace armnn namespace profiling { -uint16_t GetNextUid() +namespace { - // Static mutex for reading and modifying the global UID a single thread at the time - static std::mutex mutex; - std::unique_lock lock(mutex); +void ThrowIfCantGenerateNextUid(uint16_t uid, uint16_t cores = 0) +{ + // Check that it is possible to generate the next UID without causing an overflow + switch (cores) + { + case 0: + case 1: + // Number of cores not specified or set to 1 (a value of zero indicates the device is not capable of + // running multiple parallel workloads and will not provide multiple streams of data for each event) + if (uid == std::numeric_limits::max()) + { + throw RuntimeException("Generating the next UID for profiling would result in an overflow"); + } + break; + default: // cores > 1 + // Multiple cores available, as max_counter_uid has to be set to: counter_uid + cores - 1, the maximum + // allowed value for a counter UID is consequently: uint16_t_max - cores + 1 + if (uid >= std::numeric_limits::max() - cores + 1) + { + throw RuntimeException("Generating the next UID for profiling would result in an overflow"); + } + break; + } +} + +} // Anonymous namespace + +uint16_t GetNextUid(bool peekOnly) +{ // The UID used for profiling objects and events. The first valid UID is 1, as 0 is a reserved value - // (it is used to indicate that a record is not associated with any device) - static uint16_t uid{ 0 }; + static uint16_t uid = 1; - // Check that it is possible to generate the next UID without causing an overflow - if (uid == std::numeric_limits::max()) + // Check that it is possible to generate the next UID without causing an overflow (throws in case of error) + ThrowIfCantGenerateNextUid(uid); + + if (peekOnly) + { + // Peek only + return uid; + } + else { - throw RuntimeException("Generating the next UID for profiling would result in an overflow"); + // Get the next UID + return uid++; } +} - // Thread safe increment, the value that is incremented is the value checked for overflow, - // as this whole function is mutexed - return ++uid; +std::vector GetNextCounterUids(uint16_t cores) +{ + // The UID used for counters only. The first valid UID is 0 + static uint16_t counterUid = 0; + + // Check that it is possible to generate the next counter UID without causing an overflow (throws in case of error) + ThrowIfCantGenerateNextUid(counterUid, cores); + + // Get the next counter UIDs + size_t counterUidsSize = cores == 0 ? 1 : cores; + std::vector counterUids(counterUidsSize, 0); + for (size_t i = 0; i < counterUidsSize; i++) + { + counterUids[i] = counterUid++; + } + return counterUids; } void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value) diff --git a/src/profiling/ProfilingUtils.hpp b/src/profiling/ProfilingUtils.hpp index 0e94e612d9..793f94d91b 100644 --- a/src/profiling/ProfilingUtils.hpp +++ b/src/profiling/ProfilingUtils.hpp @@ -7,8 +7,12 @@ #include +#include + #include -#include +#include +#include +#include namespace armnn { @@ -16,7 +20,65 @@ namespace armnn namespace profiling { -uint16_t GetNextUid(); +struct SwTraceCharPolicy +{ + static bool IsValidChar(unsigned char c) + { + // Check that the given character has ASCII 7-bit encoding + return c < 128; + } +}; + +struct SwTraceNameCharPolicy +{ + static bool IsValidChar(unsigned char c) + { + // Check that the given character has ASCII 7-bit encoding, alpha-numeric and underscore only + return c < 128 && (std::isalnum(c) || c == '_'); + } +}; + +template +bool IsValidSwTraceString(const std::string& s) +{ + // Check that all the characters in the given string conform to the given policy + return std::all_of(s.begin(), s.end(), [](unsigned char c) + { + return SwTracePolicy::IsValidChar(c); + }); +} + +template +bool StringToSwTraceString(const std::string& s, std::vector& outputBuffer) +{ + // Converts the given string to an SWTrace "string" (i.e. a string of "chars"), and writes it into + // the given buffer including the null-terminator. It also pads it to the next uint32_t if necessary + + // Clear the output buffer + outputBuffer.clear(); + + // Check that the given string is a valid SWTrace "string" (i.e. a string of "chars") + if (!IsValidSwTraceString(s)) + { + return false; + } + + // Prepare the output buffer + size_t s_size = s.size() + 1; // The size of the string (in chars) plus the null-terminator + size_t uint32_t_size = sizeof(uint32_t); + size_t outBufferSize = 1 + s_size / uint32_t_size + (s_size % uint32_t_size != 0 ? 1 : 0); + outputBuffer.resize(outBufferSize, '\0'); + + // Write the SWTrace string to the output buffer + outputBuffer[0] = boost::numeric_cast(s_size); + std::memcpy(outputBuffer.data() + 1, s.data(), s_size); + + return true; +} + +uint16_t GetNextUid(bool peekOnly = false); + +std::vector GetNextCounterUids(uint16_t cores); void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value); diff --git a/src/profiling/test/ProfilingTests.cpp b/src/profiling/test/ProfilingTests.cpp index 55524a4dfe..d16479a46c 100644 --- a/src/profiling/test/ProfilingTests.cpp +++ b/src/profiling/test/ProfilingTests.cpp @@ -3,23 +3,24 @@ // SPDX-License-Identifier: MIT // -#include "../CommandHandlerKey.hpp" -#include "../CommandHandlerFunctor.hpp" -#include "../CommandHandlerRegistry.hpp" -#include "../EncodeVersion.hpp" -#include "../Holder.hpp" -#include "../Packet.hpp" -#include "../PacketVersionResolver.hpp" -#include "../ProfilingService.hpp" -#include "../ProfilingStateMachine.hpp" -#include "../PeriodicCounterSelectionCommandHandler.hpp" -#include "../ProfilingUtils.hpp" -#include "../SocketProfilingConnection.hpp" -#include "../IPeriodicCounterCapture.hpp" #include "SendCounterPacketTests.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include #include @@ -538,30 +539,909 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceEnabledRuntime) BOOST_CHECK(service.GetCurrentState() == ProfilingState::WaitingForAck); } -void GetNextUidTestImpl(uint16_t& outUid) +BOOST_AUTO_TEST_CASE(CheckProfilingObjectUids) { - outUid = GetNextUid(); + uint16_t uid = 0; + BOOST_CHECK_NO_THROW(uid = GetNextUid()); + BOOST_CHECK(uid >= 1); + + uint16_t nextUid = 0; + BOOST_CHECK_NO_THROW(nextUid = GetNextUid()); + BOOST_CHECK(nextUid > uid); + + std::vector counterUids; + BOOST_CHECK_NO_THROW(counterUids = GetNextCounterUids(0)); + BOOST_CHECK(counterUids.size() == 1); + BOOST_CHECK(counterUids[0] >= 0); + + std::vector nextCounterUids; + BOOST_CHECK_NO_THROW(nextCounterUids = GetNextCounterUids(1)); + BOOST_CHECK(nextCounterUids.size() == 1); + BOOST_CHECK(nextCounterUids[0] > counterUids[0]); + + std::vector counterUidsMultiCore; + uint16_t numberOfCores = 13; + BOOST_CHECK_NO_THROW(counterUidsMultiCore = GetNextCounterUids(numberOfCores)); + BOOST_CHECK(counterUidsMultiCore.size() == numberOfCores); + BOOST_CHECK(counterUidsMultiCore.front() >= nextCounterUids[0]); + for (size_t i = 1; i < numberOfCores; i ++) + { + BOOST_CHECK(counterUidsMultiCore[i] == counterUidsMultiCore[i - 1] + 1); + } + BOOST_CHECK(counterUidsMultiCore.back() == counterUidsMultiCore.front() + numberOfCores - 1); } -BOOST_AUTO_TEST_CASE(GetNextUidTest) +BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterCategory) { - uint16_t uid0 = 0; - uint16_t uid1 = 0; - uint16_t uid2 = 0; + CounterDirectory counterDirectory; + BOOST_CHECK(counterDirectory.GetCategoryCount() == 0); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + + // Register a category with an invalid name + const Category* noCategory = nullptr; + BOOST_CHECK_THROW(noCategory = counterDirectory.RegisterCategory(""), armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 0); + BOOST_CHECK(!noCategory); + + // Register a category with an invalid name + BOOST_CHECK_THROW(noCategory = counterDirectory.RegisterCategory("invalid category"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 0); + BOOST_CHECK(!noCategory); + + // Register a new category + const std::string categoryName = "some_category"; + const Category* category = nullptr; + BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 1); + BOOST_CHECK(category); + BOOST_CHECK(category->m_Name == categoryName); + BOOST_CHECK(category->m_Counters.empty()); + BOOST_CHECK(category->m_DeviceUid == 0); + BOOST_CHECK(category->m_CounterSetUid == 0); + + // Get the registered category + const Category* registeredCategory = counterDirectory.GetCategory(categoryName); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 1); + BOOST_CHECK(registeredCategory); + BOOST_CHECK(registeredCategory == category); + + // Try to get a category not registered + const Category* notRegisteredCategory = counterDirectory.GetCategory("not_registered_category"); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 1); + BOOST_CHECK(!notRegisteredCategory); + + // Register a category already registered + const Category* anotherCategory = nullptr; + BOOST_CHECK_THROW(anotherCategory = counterDirectory.RegisterCategory(categoryName), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 1); + BOOST_CHECK(!anotherCategory); + + // Register a device for testing + const std::string deviceName = "some_device"; + const Device* device = nullptr; + BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName)); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 1); + BOOST_CHECK(device); + BOOST_CHECK(device->m_Uid >= 1); + BOOST_CHECK(device->m_Name == deviceName); + BOOST_CHECK(device->m_Cores == 0); + + // Register a new category not associated to any device + const std::string categoryWoDeviceName = "some_category_without_device"; + const Category* categoryWoDevice = nullptr; + BOOST_CHECK_NO_THROW(categoryWoDevice = counterDirectory.RegisterCategory(categoryWoDeviceName, 0)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 2); + BOOST_CHECK(categoryWoDevice); + BOOST_CHECK(categoryWoDevice->m_Name == categoryWoDeviceName); + BOOST_CHECK(categoryWoDevice->m_Counters.empty()); + BOOST_CHECK(categoryWoDevice->m_DeviceUid == 0); + BOOST_CHECK(categoryWoDevice->m_CounterSetUid == 0); + + // Register a new category associated to an invalid device + const std::string categoryWInvalidDeviceName = "some_category_with_invalid_device"; + + ARMNN_NO_CONVERSION_WARN_BEGIN + uint16_t invalidDeviceUid = device->m_Uid + 10; + ARMNN_NO_CONVERSION_WARN_END + + const Category* categoryWInvalidDevice = nullptr; + BOOST_CHECK_THROW(categoryWInvalidDevice + = counterDirectory.RegisterCategory(categoryWInvalidDeviceName, + invalidDeviceUid), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 2); + BOOST_CHECK(!categoryWInvalidDevice); + + // Register a new category associated to a valid device + const std::string categoryWValidDeviceName = "some_category_with_valid_device"; + const Category* categoryWValidDevice = nullptr; + BOOST_CHECK_NO_THROW(categoryWValidDevice + = counterDirectory.RegisterCategory(categoryWValidDeviceName, + device->m_Uid)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 3); + BOOST_CHECK(categoryWValidDevice); + BOOST_CHECK(categoryWValidDevice != category); + BOOST_CHECK(categoryWValidDevice->m_Name == categoryWValidDeviceName); + BOOST_CHECK(categoryWValidDevice->m_DeviceUid == device->m_Uid); + BOOST_CHECK(categoryWValidDevice->m_CounterSetUid == 0); + + // Register a counter set for testing + const std::string counterSetName = "some_counter_set"; + const CounterSet* counterSet = nullptr; + BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName)); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1); + BOOST_CHECK(counterSet); + BOOST_CHECK(counterSet->m_Uid >= 1); + BOOST_CHECK(counterSet->m_Name == counterSetName); + BOOST_CHECK(counterSet->m_Count == 0); + + // Register a new category not associated to any counter set + const std::string categoryWoCounterSetName = "some_category_without_counter_set"; + const Category* categoryWoCounterSet = nullptr; + BOOST_CHECK_NO_THROW(categoryWoCounterSet + = counterDirectory.RegisterCategory(categoryWoCounterSetName, + armnn::EmptyOptional(), + 0)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 4); + BOOST_CHECK(categoryWoCounterSet); + BOOST_CHECK(categoryWoCounterSet->m_Name == categoryWoCounterSetName); + BOOST_CHECK(categoryWoCounterSet->m_DeviceUid == 0); + BOOST_CHECK(categoryWoCounterSet->m_CounterSetUid == 0); + + // Register a new category associated to an invalid counter set + const std::string categoryWInvalidCounterSetName = "some_category_with_invalid_counter_set"; + + ARMNN_NO_CONVERSION_WARN_BEGIN + uint16_t invalidCunterSetUid = counterSet->m_Uid + 10; + ARMNN_NO_CONVERSION_WARN_END + + const Category* categoryWInvalidCounterSet = nullptr; + BOOST_CHECK_THROW(categoryWInvalidCounterSet + = counterDirectory.RegisterCategory(categoryWInvalidCounterSetName, + armnn::EmptyOptional(), + invalidCunterSetUid), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 4); + BOOST_CHECK(!categoryWInvalidCounterSet); + + // Register a new category associated to a valid counter set + const std::string categoryWValidCounterSetName = "some_category_with_valid_counter_set"; + const Category* categoryWValidCounterSet = nullptr; + BOOST_CHECK_NO_THROW(categoryWValidCounterSet + = counterDirectory.RegisterCategory(categoryWValidCounterSetName, + armnn::EmptyOptional(), + counterSet->m_Uid)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 5); + BOOST_CHECK(categoryWValidCounterSet); + BOOST_CHECK(categoryWValidCounterSet != category); + BOOST_CHECK(categoryWValidCounterSet->m_Name == categoryWValidCounterSetName); + BOOST_CHECK(categoryWValidCounterSet->m_DeviceUid == 0); + BOOST_CHECK(categoryWValidCounterSet->m_CounterSetUid == counterSet->m_Uid); + + // Register a new category associated to a valid device and counter set + const std::string categoryWValidDeviceAndValidCounterSetName = "some_category_with_valid_device_and_counter_set"; + const Category* categoryWValidDeviceAndValidCounterSet = nullptr; + BOOST_CHECK_NO_THROW(categoryWValidDeviceAndValidCounterSet + = counterDirectory.RegisterCategory(categoryWValidDeviceAndValidCounterSetName, + device->m_Uid, + counterSet->m_Uid)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 6); + BOOST_CHECK(categoryWValidDeviceAndValidCounterSet); + BOOST_CHECK(categoryWValidDeviceAndValidCounterSet != category); + BOOST_CHECK(categoryWValidDeviceAndValidCounterSet->m_Name == categoryWValidDeviceAndValidCounterSetName); + BOOST_CHECK(categoryWValidDeviceAndValidCounterSet->m_DeviceUid == device->m_Uid); + BOOST_CHECK(categoryWValidDeviceAndValidCounterSet->m_CounterSetUid == counterSet->m_Uid); +} - std::thread thread1(GetNextUidTestImpl, std::ref(uid0)); - std::thread thread2(GetNextUidTestImpl, std::ref(uid1)); - std::thread thread3(GetNextUidTestImpl, std::ref(uid2)); - thread1.join(); - thread2.join(); - thread3.join(); +BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterDevice) +{ + CounterDirectory counterDirectory; + BOOST_CHECK(counterDirectory.GetCategoryCount() == 0); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + + // Register a device with an invalid name + const Device* noDevice = nullptr; + BOOST_CHECK_THROW(noDevice = counterDirectory.RegisterDevice(""), armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 0); + BOOST_CHECK(!noDevice); + + // Register a device with an invalid name + BOOST_CHECK_THROW(noDevice = counterDirectory.RegisterDevice("inv@lid nam€"), armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 0); + BOOST_CHECK(!noDevice); + + // Register a new device with no cores or parent category + const std::string deviceName = "some_device"; + const Device* device = nullptr; + BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName)); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 1); + BOOST_CHECK(device); + BOOST_CHECK(device->m_Name == deviceName); + BOOST_CHECK(device->m_Uid >= 1); + BOOST_CHECK(device->m_Cores == 0); + + // Get the registered device + const Device* registeredDevice = counterDirectory.GetDevice(device->m_Uid); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 1); + BOOST_CHECK(registeredDevice); + BOOST_CHECK(registeredDevice == device); + + // Register a new device with cores and no parent category + const std::string deviceWCoresName = "some_device_with_cores"; + const Device* deviceWCores = nullptr; + BOOST_CHECK_NO_THROW(deviceWCores = counterDirectory.RegisterDevice(deviceWCoresName, 2)); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 2); + BOOST_CHECK(deviceWCores); + BOOST_CHECK(deviceWCores->m_Name == deviceWCoresName); + BOOST_CHECK(deviceWCores->m_Uid >= 1); + BOOST_CHECK(deviceWCores->m_Uid > device->m_Uid); + BOOST_CHECK(deviceWCores->m_Cores == 2); + + // Get the registered device + const Device* registeredDeviceWCores = counterDirectory.GetDevice(deviceWCores->m_Uid); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 2); + BOOST_CHECK(registeredDeviceWCores); + BOOST_CHECK(registeredDeviceWCores == deviceWCores); + BOOST_CHECK(registeredDeviceWCores != device); + + // Register a new device with cores and invalid parent category + const std::string deviceWCoresWInvalidParentCategoryName = "some_device_with_cores_with_invalid_parent_category"; + const Device* deviceWCoresWInvalidParentCategory = nullptr; + BOOST_CHECK_THROW(deviceWCoresWInvalidParentCategory + = counterDirectory.RegisterDevice(deviceWCoresWInvalidParentCategoryName, + 3, + std::string("")), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 2); + BOOST_CHECK(!deviceWCoresWInvalidParentCategory); + + // Register a new device with cores and invalid parent category + const std::string deviceWCoresWInvalidParentCategoryName2 = "some_device_with_cores_with_invalid_parent_category2"; + const Device* deviceWCoresWInvalidParentCategory2 = nullptr; + BOOST_CHECK_THROW(deviceWCoresWInvalidParentCategory2 + = counterDirectory.RegisterDevice(deviceWCoresWInvalidParentCategoryName2, + 3, + std::string("invalid_parent_category")), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 2); + BOOST_CHECK(!deviceWCoresWInvalidParentCategory2); + + // Register a category for testing + const std::string categoryName = "some_category"; + const Category* category = nullptr; + BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 1); + BOOST_CHECK(category); + BOOST_CHECK(category->m_Name == categoryName); + BOOST_CHECK(category->m_Counters.empty()); + BOOST_CHECK(category->m_DeviceUid == 0); + BOOST_CHECK(category->m_CounterSetUid == 0); + + // Register a new device with cores and valid parent category + const std::string deviceWCoresWValidParentCategoryName = "some_device_with_cores_with_valid_parent_category"; + const Device* deviceWCoresWValidParentCategory = nullptr; + BOOST_CHECK_NO_THROW(deviceWCoresWValidParentCategory + = counterDirectory.RegisterDevice(deviceWCoresWValidParentCategoryName, + 4, + categoryName)); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 3); + BOOST_CHECK(deviceWCoresWValidParentCategory); + BOOST_CHECK(deviceWCoresWValidParentCategory->m_Name == deviceWCoresWValidParentCategoryName); + BOOST_CHECK(deviceWCoresWValidParentCategory->m_Uid >= 1); + BOOST_CHECK(deviceWCoresWValidParentCategory->m_Uid > device->m_Uid); + BOOST_CHECK(deviceWCoresWValidParentCategory->m_Uid > deviceWCores->m_Uid); + BOOST_CHECK(deviceWCoresWValidParentCategory->m_Cores == 4); + BOOST_CHECK(category->m_DeviceUid == deviceWCoresWValidParentCategory->m_Uid); +} + +BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterCounterSet) +{ + CounterDirectory counterDirectory; + BOOST_CHECK(counterDirectory.GetCategoryCount() == 0); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + + // Register a counter set with an invalid name + const CounterSet* noCounterSet = nullptr; + BOOST_CHECK_THROW(noCounterSet = counterDirectory.RegisterCounterSet(""), armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0); + BOOST_CHECK(!noCounterSet); + + // Register a counter set with an invalid name + BOOST_CHECK_THROW(noCounterSet = counterDirectory.RegisterCounterSet("invalid name"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0); + BOOST_CHECK(!noCounterSet); + + // Register a new counter set with no count or parent category + const std::string counterSetName = "some_counter_set"; + const CounterSet* counterSet = nullptr; + BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName)); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1); + BOOST_CHECK(counterSet); + BOOST_CHECK(counterSet->m_Name == counterSetName); + BOOST_CHECK(counterSet->m_Uid >= 1); + BOOST_CHECK(counterSet->m_Count == 0); + + // Get the registered counter set + const CounterSet* registeredCounterSet = counterDirectory.GetCounterSet(counterSet->m_Uid); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1); + BOOST_CHECK(registeredCounterSet); + BOOST_CHECK(registeredCounterSet == counterSet); + + // Register a new counter set with count and no parent category + const std::string counterSetWCountName = "some_counter_set_with_count"; + const CounterSet* counterSetWCount = nullptr; + BOOST_CHECK_NO_THROW(counterSetWCount = counterDirectory.RegisterCounterSet(counterSetWCountName, 37)); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2); + BOOST_CHECK(counterSetWCount); + BOOST_CHECK(counterSetWCount->m_Name == counterSetWCountName); + BOOST_CHECK(counterSetWCount->m_Uid >= 1); + BOOST_CHECK(counterSetWCount->m_Uid > counterSet->m_Uid); + BOOST_CHECK(counterSetWCount->m_Count == 37); + + // Get the registered counter set + const CounterSet* registeredCounterSetWCount = counterDirectory.GetCounterSet(counterSetWCount->m_Uid); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2); + BOOST_CHECK(registeredCounterSetWCount); + BOOST_CHECK(registeredCounterSetWCount == counterSetWCount); + BOOST_CHECK(registeredCounterSetWCount != counterSet); + + // Register a new counter set with count and invalid parent category + const std::string counterSetWCountWInvalidParentCategoryName = "some_counter_set_with_count_" + "with_invalid_parent_category"; + const CounterSet* counterSetWCountWInvalidParentCategory = nullptr; + BOOST_CHECK_THROW(counterSetWCountWInvalidParentCategory + = counterDirectory.RegisterCounterSet(counterSetWCountWInvalidParentCategoryName, + 42, + std::string("")), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2); + BOOST_CHECK(!counterSetWCountWInvalidParentCategory); + + // Register a new counter set with count and invalid parent category + const std::string counterSetWCountWInvalidParentCategoryName2 = "some_counter_set_with_count_" + "with_invalid_parent_category2"; + const CounterSet* counterSetWCountWInvalidParentCategory2 = nullptr; + BOOST_CHECK_THROW(counterSetWCountWInvalidParentCategory2 + = counterDirectory.RegisterCounterSet(counterSetWCountWInvalidParentCategoryName2, + 42, + std::string("invalid_parent_category")), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 2); + BOOST_CHECK(!counterSetWCountWInvalidParentCategory2); + + // Register a category for testing + const std::string categoryName = "some_category"; + const Category* category = nullptr; + BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 1); + BOOST_CHECK(category); + BOOST_CHECK(category->m_Name == categoryName); + BOOST_CHECK(category->m_Counters.empty()); + BOOST_CHECK(category->m_DeviceUid == 0); + BOOST_CHECK(category->m_CounterSetUid == 0); + + // Register a new counter set with count and valid parent category + const std::string counterSetWCountWValidParentCategoryName = "some_counter_set_with_count_" + "with_valid_parent_category"; + const CounterSet* counterSetWCountWValidParentCategory = nullptr; + BOOST_CHECK_NO_THROW(counterSetWCountWValidParentCategory + = counterDirectory.RegisterCounterSet(counterSetWCountWValidParentCategoryName, + 42, + std::string(categoryName))); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 3); + BOOST_CHECK(counterSetWCountWValidParentCategory); + BOOST_CHECK(counterSetWCountWValidParentCategory->m_Name == counterSetWCountWValidParentCategoryName); + BOOST_CHECK(counterSetWCountWValidParentCategory->m_Uid >= 1); + BOOST_CHECK(counterSetWCountWValidParentCategory->m_Uid > counterSet->m_Uid); + BOOST_CHECK(counterSetWCountWValidParentCategory->m_Uid > counterSetWCount->m_Uid); + BOOST_CHECK(counterSetWCountWValidParentCategory->m_Count == 42); + BOOST_CHECK(category->m_CounterSetUid == counterSetWCountWValidParentCategory->m_Uid); +} + +BOOST_AUTO_TEST_CASE(CheckCounterDirectoryRegisterCounter) +{ + CounterDirectory counterDirectory; + BOOST_CHECK(counterDirectory.GetCategoryCount() == 0); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 0); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + + // Register a counter with an invalid parent category name + const Counter* noCounter = nullptr; + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("", + 0, + 1, + 123.45f, + "valid name", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid parent category name + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("invalid parent category", + 0, + 1, + 123.45f, + "valid name", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid class + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 2, + 1, + 123.45f, + "valid name", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid interpolation + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 0, + 3, + 123.45f, + "valid name", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid multiplier + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 0, + 1, + .0f, + "valid name", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid name + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 0, + 1, + 123.45f, + "", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid name + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 0, + 1, + 123.45f, + "invalid nam€", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid description + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 0, + 1, + 123.45f, + "valid name", + ""), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid description + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 0, + 1, + 123.45f, + "valid name", + "inv@lid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with an invalid unit2 + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("valid_parent_category", + 0, + 1, + 123.45f, + "valid name", + "valid description", + std::string("Mb/s2")), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a counter with a non-existing parent category name + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter("invalid_parent_category", + 0, + 1, + 123.45f, + "valid name", + "valid description"), + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 0); + BOOST_CHECK(!noCounter); + + // Register a category for testing + const std::string categoryName = "some_category"; + const Category* category = nullptr; + BOOST_CHECK_NO_THROW(category = counterDirectory.RegisterCategory(categoryName)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 1); + BOOST_CHECK(category); + BOOST_CHECK(category->m_Name == categoryName); + BOOST_CHECK(category->m_Counters.empty()); + BOOST_CHECK(category->m_DeviceUid == 0); + BOOST_CHECK(category->m_CounterSetUid == 0); + + // Register a counter with a valid parent category name + const Counter* counter = nullptr; + BOOST_CHECK_NO_THROW(counter = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name", + "valid description")); + BOOST_CHECK(counterDirectory.GetCounterCount() == 1); + BOOST_CHECK(counter); + BOOST_CHECK(counter->m_Uid >= 0); + BOOST_CHECK(counter->m_MaxCounterUid == counter->m_Uid); + BOOST_CHECK(counter->m_Class == 0); + BOOST_CHECK(counter->m_Interpolation == 1); + BOOST_CHECK(counter->m_Multiplier == 123.45f); + BOOST_CHECK(counter->m_Name == "valid name"); + BOOST_CHECK(counter->m_Description == "valid description"); + BOOST_CHECK(counter->m_Units == ""); + BOOST_CHECK(counter->m_DeviceUid == 0); + BOOST_CHECK(counter->m_CounterSetUid == 0); + BOOST_CHECK(category->m_Counters.size() == 1); + BOOST_CHECK(category->m_Counters.back() == counter->m_Uid); + + // Register a counter with a valid parent category name and units + const Counter* counterWUnits = nullptr; + BOOST_CHECK_NO_THROW(counterWUnits = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 2", + "valid description", + std::string("Mnnsq2"))); // Units + BOOST_CHECK(counterDirectory.GetCounterCount() == 2); + BOOST_CHECK(counterWUnits); + BOOST_CHECK(counterWUnits->m_Uid >= 0); + BOOST_CHECK(counterWUnits->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWUnits->m_MaxCounterUid == counterWUnits->m_Uid); + BOOST_CHECK(counterWUnits->m_Class == 0); + BOOST_CHECK(counterWUnits->m_Interpolation == 1); + BOOST_CHECK(counterWUnits->m_Multiplier == 123.45f); + BOOST_CHECK(counterWUnits->m_Name == "valid name 2"); + BOOST_CHECK(counterWUnits->m_Description == "valid description"); + BOOST_CHECK(counterWUnits->m_Units == "Mnnsq2"); + BOOST_CHECK(counterWUnits->m_DeviceUid == 0); + BOOST_CHECK(counterWUnits->m_CounterSetUid == 0); + BOOST_CHECK(category->m_Counters.size() == 2); + BOOST_CHECK(category->m_Counters.back() == counterWUnits->m_Uid); + + // Register a counter with a valid parent category name and not associated with a device + const Counter* counterWoDevice = nullptr; + BOOST_CHECK_NO_THROW(counterWoDevice = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 3", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + 0)); // Device UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 3); + BOOST_CHECK(counterWoDevice); + BOOST_CHECK(counterWoDevice->m_Uid >= 0); + BOOST_CHECK(counterWoDevice->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWoDevice->m_MaxCounterUid == counterWoDevice->m_Uid); + BOOST_CHECK(counterWoDevice->m_Class == 0); + BOOST_CHECK(counterWoDevice->m_Interpolation == 1); + BOOST_CHECK(counterWoDevice->m_Multiplier == 123.45f); + BOOST_CHECK(counterWoDevice->m_Name == "valid name 3"); + BOOST_CHECK(counterWoDevice->m_Description == "valid description"); + BOOST_CHECK(counterWoDevice->m_Units == ""); + BOOST_CHECK(counterWoDevice->m_DeviceUid == 0); + BOOST_CHECK(counterWoDevice->m_CounterSetUid == 0); + BOOST_CHECK(category->m_Counters.size() == 3); + BOOST_CHECK(category->m_Counters.back() == counterWoDevice->m_Uid); + + // Register a counter with a valid parent category name and associated to an invalid device + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 4", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + 100), // Device UID + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 3); + BOOST_CHECK(!noCounter); + + // Register a device for testing + const std::string deviceName = "some_device"; + const Device* device = nullptr; + BOOST_CHECK_NO_THROW(device = counterDirectory.RegisterDevice(deviceName)); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 1); + BOOST_CHECK(device); + BOOST_CHECK(device->m_Name == deviceName); + BOOST_CHECK(device->m_Uid >= 1); + BOOST_CHECK(device->m_Cores == 0); + + // Register a counter with a valid parent category name and associated to a device + const Counter* counterWDevice = nullptr; + BOOST_CHECK_NO_THROW(counterWDevice = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 5", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + device->m_Uid)); // Device UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 4); + BOOST_CHECK(counterWDevice); + BOOST_CHECK(counterWDevice->m_Uid >= 0); + BOOST_CHECK(counterWDevice->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWDevice->m_MaxCounterUid == counterWDevice->m_Uid); + BOOST_CHECK(counterWDevice->m_Class == 0); + BOOST_CHECK(counterWDevice->m_Interpolation == 1); + BOOST_CHECK(counterWDevice->m_Multiplier == 123.45f); + BOOST_CHECK(counterWDevice->m_Name == "valid name 5"); + BOOST_CHECK(counterWDevice->m_Description == "valid description"); + BOOST_CHECK(counterWDevice->m_Units == ""); + BOOST_CHECK(counterWDevice->m_DeviceUid == device->m_Uid); + BOOST_CHECK(counterWDevice->m_CounterSetUid == 0); + BOOST_CHECK(category->m_Counters.size() == 4); + BOOST_CHECK(category->m_Counters.back() == counterWDevice->m_Uid); + + // Register a counter with a valid parent category name and not associated with a counter set + const Counter* counterWoCounterSet = nullptr; + BOOST_CHECK_NO_THROW(counterWoCounterSet + = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 6", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + armnn::EmptyOptional(), // Device UID + 0)); // Counter set UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 5); + BOOST_CHECK(counterWoCounterSet); + BOOST_CHECK(counterWoCounterSet->m_Uid >= 0); + BOOST_CHECK(counterWoCounterSet->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWoCounterSet->m_MaxCounterUid == counterWoCounterSet->m_Uid); + BOOST_CHECK(counterWoCounterSet->m_Class == 0); + BOOST_CHECK(counterWoCounterSet->m_Interpolation == 1); + BOOST_CHECK(counterWoCounterSet->m_Multiplier == 123.45f); + BOOST_CHECK(counterWoCounterSet->m_Name == "valid name 6"); + BOOST_CHECK(counterWoCounterSet->m_Description == "valid description"); + BOOST_CHECK(counterWoCounterSet->m_Units == ""); + BOOST_CHECK(counterWoCounterSet->m_DeviceUid == 0); + BOOST_CHECK(counterWoCounterSet->m_CounterSetUid == 0); + BOOST_CHECK(category->m_Counters.size() == 5); + BOOST_CHECK(category->m_Counters.back() == counterWoCounterSet->m_Uid); + + // Register a counter with a valid parent category name and associated to an invalid counter set + BOOST_CHECK_THROW(noCounter = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 7", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + armnn::EmptyOptional(), // Device UID + 100), // Counter set UID + armnn::InvalidArgumentException); + BOOST_CHECK(counterDirectory.GetCounterCount() == 5); + BOOST_CHECK(!noCounter); + + // Register a counter with a valid parent category name and with a given number of cores + const Counter* counterWNumberOfCores = nullptr; + uint16_t numberOfCores = 15; + BOOST_CHECK_NO_THROW(counterWNumberOfCores + = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 8", + "valid description", + armnn::EmptyOptional(), // Units + numberOfCores, // Number of cores + armnn::EmptyOptional(), // Device UID + armnn::EmptyOptional())); // Counter set UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 20); + BOOST_CHECK(counterWNumberOfCores); + BOOST_CHECK(counterWNumberOfCores->m_Uid >= 0); + BOOST_CHECK(counterWNumberOfCores->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWNumberOfCores->m_MaxCounterUid == counterWNumberOfCores->m_Uid + numberOfCores - 1); + BOOST_CHECK(counterWNumberOfCores->m_Class == 0); + BOOST_CHECK(counterWNumberOfCores->m_Interpolation == 1); + BOOST_CHECK(counterWNumberOfCores->m_Multiplier == 123.45f); + BOOST_CHECK(counterWNumberOfCores->m_Name == "valid name 8"); + BOOST_CHECK(counterWNumberOfCores->m_Description == "valid description"); + BOOST_CHECK(counterWNumberOfCores->m_Units == ""); + BOOST_CHECK(counterWNumberOfCores->m_DeviceUid == 0); + BOOST_CHECK(counterWNumberOfCores->m_CounterSetUid == 0); + BOOST_CHECK(category->m_Counters.size() == 20); + for (size_t i = 0; i < numberOfCores; i ++) + { + BOOST_CHECK(category->m_Counters[category->m_Counters.size() - numberOfCores + i] == + counterWNumberOfCores->m_Uid + i); + } + + // Register a multi-core device for testing + const std::string multiCoreDeviceName = "some_multi_core_device"; + const Device* multiCoreDevice = nullptr; + BOOST_CHECK_NO_THROW(multiCoreDevice = counterDirectory.RegisterDevice(multiCoreDeviceName, 4)); + BOOST_CHECK(counterDirectory.GetDeviceCount() == 2); + BOOST_CHECK(multiCoreDevice); + BOOST_CHECK(multiCoreDevice->m_Name == multiCoreDeviceName); + BOOST_CHECK(multiCoreDevice->m_Uid >= 1); + BOOST_CHECK(multiCoreDevice->m_Cores == 4); + + // Register a counter with a valid parent category name and associated to the multi-core device + const Counter* counterWMultiCoreDevice = nullptr; + BOOST_CHECK_NO_THROW(counterWMultiCoreDevice + = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 9", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + multiCoreDevice->m_Uid, // Device UID + armnn::EmptyOptional())); // Counter set UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 24); + BOOST_CHECK(counterWMultiCoreDevice); + BOOST_CHECK(counterWMultiCoreDevice->m_Uid >= 0); + BOOST_CHECK(counterWMultiCoreDevice->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWMultiCoreDevice->m_MaxCounterUid == + counterWMultiCoreDevice->m_Uid + multiCoreDevice->m_Cores - 1); + BOOST_CHECK(counterWMultiCoreDevice->m_Class == 0); + BOOST_CHECK(counterWMultiCoreDevice->m_Interpolation == 1); + BOOST_CHECK(counterWMultiCoreDevice->m_Multiplier == 123.45f); + BOOST_CHECK(counterWMultiCoreDevice->m_Name == "valid name 9"); + BOOST_CHECK(counterWMultiCoreDevice->m_Description == "valid description"); + BOOST_CHECK(counterWMultiCoreDevice->m_Units == ""); + BOOST_CHECK(counterWMultiCoreDevice->m_DeviceUid == multiCoreDevice->m_Uid); + BOOST_CHECK(counterWMultiCoreDevice->m_CounterSetUid == 0); + BOOST_CHECK(category->m_Counters.size() == 24); + for (size_t i = 0; i < 4; i ++) + { + BOOST_CHECK(category->m_Counters[category->m_Counters.size() - 4 + i] == counterWMultiCoreDevice->m_Uid + i); + } - BOOST_TEST(uid0 > 0); - BOOST_TEST(uid1 > 0); - BOOST_TEST(uid2 > 0); - BOOST_TEST(uid0 != uid1); - BOOST_TEST(uid0 != uid2); - BOOST_TEST(uid1 != uid2); + // Register a counter set for testing + const std::string counterSetName = "some_counter_set"; + const CounterSet* counterSet = nullptr; + BOOST_CHECK_NO_THROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName)); + BOOST_CHECK(counterDirectory.GetCounterSetCount() == 1); + BOOST_CHECK(counterSet); + BOOST_CHECK(counterSet->m_Name == counterSetName); + BOOST_CHECK(counterSet->m_Uid >= 1); + BOOST_CHECK(counterSet->m_Count == 0); + + // Register a counter with a valid parent category name and associated to a counter set + const Counter* counterWCounterSet = nullptr; + BOOST_CHECK_NO_THROW(counterWCounterSet + = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 10", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + armnn::EmptyOptional(), // Device UID + counterSet->m_Uid)); // Counter set UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 25); + BOOST_CHECK(counterWCounterSet); + BOOST_CHECK(counterWCounterSet->m_Uid >= 0); + BOOST_CHECK(counterWCounterSet->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWCounterSet->m_MaxCounterUid == counterWCounterSet->m_Uid); + BOOST_CHECK(counterWCounterSet->m_Class == 0); + BOOST_CHECK(counterWCounterSet->m_Interpolation == 1); + BOOST_CHECK(counterWCounterSet->m_Multiplier == 123.45f); + BOOST_CHECK(counterWCounterSet->m_Name == "valid name 10"); + BOOST_CHECK(counterWCounterSet->m_Description == "valid description"); + BOOST_CHECK(counterWCounterSet->m_Units == ""); + BOOST_CHECK(counterWCounterSet->m_DeviceUid == 0); + BOOST_CHECK(counterWCounterSet->m_CounterSetUid == counterSet->m_Uid); + BOOST_CHECK(category->m_Counters.size() == 25); + BOOST_CHECK(category->m_Counters.back() == counterWCounterSet->m_Uid); + + // Register a counter with a valid parent category name and associated to a device and a counter set + const Counter* counterWDeviceWCounterSet = nullptr; + BOOST_CHECK_NO_THROW(counterWDeviceWCounterSet + = counterDirectory.RegisterCounter(categoryName, + 0, + 1, + 123.45f, + "valid name 11", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + device->m_Uid, // Device UID + counterSet->m_Uid)); // Counter set UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 26); + BOOST_CHECK(counterWDeviceWCounterSet); + BOOST_CHECK(counterWDeviceWCounterSet->m_Uid >= 0); + BOOST_CHECK(counterWDeviceWCounterSet->m_Uid > counter->m_Uid); + BOOST_CHECK(counterWDeviceWCounterSet->m_MaxCounterUid == counterWDeviceWCounterSet->m_Uid); + BOOST_CHECK(counterWDeviceWCounterSet->m_Class == 0); + BOOST_CHECK(counterWDeviceWCounterSet->m_Interpolation == 1); + BOOST_CHECK(counterWDeviceWCounterSet->m_Multiplier == 123.45f); + BOOST_CHECK(counterWDeviceWCounterSet->m_Name == "valid name 11"); + BOOST_CHECK(counterWDeviceWCounterSet->m_Description == "valid description"); + BOOST_CHECK(counterWDeviceWCounterSet->m_Units == ""); + BOOST_CHECK(counterWDeviceWCounterSet->m_DeviceUid == device->m_Uid); + BOOST_CHECK(counterWDeviceWCounterSet->m_CounterSetUid == counterSet->m_Uid); + BOOST_CHECK(category->m_Counters.size() == 26); + BOOST_CHECK(category->m_Counters.back() == counterWDeviceWCounterSet->m_Uid); + + // Register another category for testing + const std::string anotherCategoryName = "some_other_category"; + const Category* anotherCategory = nullptr; + BOOST_CHECK_NO_THROW(anotherCategory = counterDirectory.RegisterCategory(anotherCategoryName)); + BOOST_CHECK(counterDirectory.GetCategoryCount() == 2); + BOOST_CHECK(anotherCategory); + BOOST_CHECK(anotherCategory != category); + BOOST_CHECK(anotherCategory->m_Name == anotherCategoryName); + BOOST_CHECK(anotherCategory->m_Counters.empty()); + BOOST_CHECK(anotherCategory->m_DeviceUid == 0); + BOOST_CHECK(anotherCategory->m_CounterSetUid == 0); + + // Register a counter to the other category + const Counter* anotherCounter = nullptr; + BOOST_CHECK_NO_THROW(anotherCounter = counterDirectory.RegisterCounter(anotherCategoryName, + 1, + 0, + .00043f, + "valid name", + "valid description", + armnn::EmptyOptional(), // Units + armnn::EmptyOptional(), // Number of cores + device->m_Uid, // Device UID + counterSet->m_Uid)); // Counter set UID + BOOST_CHECK(counterDirectory.GetCounterCount() == 27); + BOOST_CHECK(anotherCounter); + BOOST_CHECK(anotherCounter->m_Uid >= 0); + BOOST_CHECK(anotherCounter->m_MaxCounterUid == anotherCounter->m_Uid); + BOOST_CHECK(anotherCounter->m_Class == 1); + BOOST_CHECK(anotherCounter->m_Interpolation == 0); + BOOST_CHECK(anotherCounter->m_Multiplier == .00043f); + BOOST_CHECK(anotherCounter->m_Name == "valid name"); + BOOST_CHECK(anotherCounter->m_Description == "valid description"); + BOOST_CHECK(anotherCounter->m_Units == ""); + BOOST_CHECK(anotherCounter->m_DeviceUid == device->m_Uid); + BOOST_CHECK(anotherCounter->m_CounterSetUid == counterSet->m_Uid); + BOOST_CHECK(anotherCategory->m_Counters.size() == 1); + BOOST_CHECK(anotherCategory->m_Counters.back() == anotherCounter->m_Uid); } BOOST_AUTO_TEST_CASE(CounterSelectionCommandHandlerParseData) diff --git a/src/profiling/test/SendCounterPacketTests.cpp b/src/profiling/test/SendCounterPacketTests.cpp index 4435ab67a3..c060f168cd 100644 --- a/src/profiling/test/SendCounterPacketTests.cpp +++ b/src/profiling/test/SendCounterPacketTests.cpp @@ -3,11 +3,12 @@ // SPDX-License-Identifier: MIT // -#include "../ProfilingUtils.hpp" -#include "../EncodeVersion.hpp" -#include "../SendCounterPacket.hpp" #include "SendCounterPacketTests.hpp" +#include +#include +#include + #include #include @@ -30,7 +31,7 @@ BOOST_AUTO_TEST_CASE(MockSendCounterPacketTest) BOOST_TEST(strcmp(buffer, "SendStreamMetaDataPacket") == 0); - CounterDirectory counterDirectory(1, "counter_directory", 0, 0, 0); + CounterDirectory counterDirectory; sendCounterPacket.SendCounterDirectoryPacket(counterDirectory); BOOST_TEST(strcmp(buffer, "SendCounterDirectoryPacket") == 0); -- cgit v1.2.1