Profiler: Runtime region name support (#2924)
* Profiler: add support for runtime region names * Profiler: fix group name collisions * Profiler: use set of GroupRegionNames * Profiler: add comments + named constant Signed-off-by: Jacob Hilliard <jhlliar@amazon.com>
This commit is contained in:
@@ -30,6 +30,12 @@ namespace AZ
|
||||
|
||||
const char* const m_groupName = nullptr;
|
||||
const char* const m_regionName = nullptr;
|
||||
|
||||
struct Hash
|
||||
{
|
||||
AZStd::size_t operator()(const GroupRegionName& name) const;
|
||||
};
|
||||
bool operator==(const GroupRegionName& other) const;
|
||||
};
|
||||
|
||||
CachedTimeRegion() = default;
|
||||
@@ -95,6 +101,9 @@ namespace AZ
|
||||
virtual void SetProfilerEnabled(bool enabled) = 0;
|
||||
|
||||
virtual bool IsProfilerEnabled() const = 0 ;
|
||||
|
||||
//! Used by AZ_ATOM_PROFILE_DYNAMIC to create GroupRegionNames with known lifetimes.
|
||||
virtual const CachedTimeRegion::GroupRegionName& InsertDynamicName(const char* groupName, const AZStd::string& regionName) = 0;
|
||||
};
|
||||
|
||||
} // namespace RPI
|
||||
@@ -120,3 +129,10 @@ namespace AZ
|
||||
#define AZ_ATOM_PROFILE_FUNCTION(groupName, regionName) \
|
||||
AZ_TRACE_METHOD(); \
|
||||
AZ_ATOM_PROFILE_TIME_GROUP_REGION(groupName, regionName) \
|
||||
|
||||
//! Macro that allows for region names to be submitted at runtime. Use sparingly - this acquires a lock and allocates new objects within a map.
|
||||
#define AZ_ATOM_PROFILE_DYNAMIC(groupName, regionName) \
|
||||
static_assert(AZStd::is_convertible_v<decltype(groupName), const char*>, "Runtime group names are not allowed, use a static string literal instead."); \
|
||||
const AZ::RHI::CachedTimeRegion::GroupRegionName& AZ_JOIN(groupRegionName, __LINE__) = \
|
||||
AZ::RHI::CpuProfiler::Get()->InsertDynamicName(groupName, regionName); \
|
||||
AZ::RHI::TimeRegion AZ_JOIN(timeRegion, __LINE__)(&AZ_JOIN(groupRegionName, __LINE__));
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/parallel/shared_mutex.h>
|
||||
#include <AzCore/std/smart_ptr/intrusive_refcount.h>
|
||||
@@ -114,9 +115,11 @@ namespace AZ
|
||||
bool IsContinuousCaptureInProgress() const final override;
|
||||
void SetProfilerEnabled(bool enabled) final override;
|
||||
bool IsProfilerEnabled() const final override;
|
||||
const CachedTimeRegion::GroupRegionName& InsertDynamicName(const char* groupName, const AZStd::string& regionName) final override;
|
||||
|
||||
private:
|
||||
static constexpr AZStd::size_t MaxFramesToSave = 2 * 60 * 120; // 2 minutes of 120fps
|
||||
static constexpr AZStd::size_t MaxRegionStringPoolSize = 16384; // Max amount of unique strings to save in the pool before throwing warnings.
|
||||
|
||||
// Lazily create and register the local thread data
|
||||
void RegisterThreadStorage();
|
||||
@@ -129,6 +132,15 @@ namespace AZ
|
||||
AZStd::vector<RHI::Ptr<CpuTimingLocalStorage>, AZ::OSStdAllocator> m_registeredThreads;
|
||||
AZStd::mutex m_threadRegisterMutex;
|
||||
|
||||
// Pool for GroupRegionNames that are generated at runtime through AZ_ATOM_PROFILE_DYNAMIC. Each unique
|
||||
// combination of group name and region name submitted will be stored in this pool to emulate static lifetime.
|
||||
AZStd::unordered_set<CachedTimeRegion::GroupRegionName, CachedTimeRegion::GroupRegionName::Hash> m_dynamicGroupRegionNamePool;
|
||||
|
||||
// String pool for storing region names submitted at runtime. Each call to AZ_ATOM_PROFILE_DYNAMIC will either construct
|
||||
// a string in this pool or use an already-existing entry.
|
||||
AZStd::unordered_set<AZStd::string> m_regionNameStringPool;
|
||||
AZStd::mutex m_dynamicNameMutex;
|
||||
|
||||
// Thread local storage, gets lazily allocated when a thread is created
|
||||
static thread_local CpuTimingLocalStorage* ms_threadLocalStorage;
|
||||
|
||||
|
||||
@@ -74,6 +74,20 @@ namespace AZ
|
||||
{
|
||||
}
|
||||
|
||||
AZStd::size_t CachedTimeRegion::GroupRegionName::Hash::operator()(const CachedTimeRegion::GroupRegionName& name) const
|
||||
{
|
||||
AZStd::size_t seed = 0;
|
||||
AZStd::hash_combine(seed, name.m_groupName);
|
||||
AZStd::hash_combine(seed, name.m_regionName);
|
||||
return seed;
|
||||
}
|
||||
|
||||
bool CachedTimeRegion::GroupRegionName::operator==(const GroupRegionName& other) const
|
||||
{
|
||||
return (m_groupName == other.m_groupName) && (m_regionName == other.m_regionName);
|
||||
}
|
||||
|
||||
|
||||
// --- CpuProfilerImpl ---
|
||||
|
||||
void CpuProfilerImpl::Init()
|
||||
@@ -218,6 +232,19 @@ namespace AZ
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
const CachedTimeRegion::GroupRegionName& CpuProfilerImpl::InsertDynamicName(const char* groupName, const AZStd::string& regionName)
|
||||
{
|
||||
AZStd::scoped_lock lock(m_dynamicNameMutex);
|
||||
AZ_Warning("CpuProfiler", m_regionNameStringPool.size() < MaxRegionStringPoolSize,
|
||||
"Stored dynamic region names are accumulating. Consider removing a AZ_ATOM_PROFILE_DYNAMIC invocation.");
|
||||
auto [regionNameItr, wasRegionInserted] = m_regionNameStringPool.insert(regionName);
|
||||
|
||||
CachedTimeRegion::GroupRegionName newGroupRegionName(groupName, regionNameItr->c_str());
|
||||
auto [groupRegionNameItr, wasGroupRegionInserted] = m_dynamicGroupRegionNamePool.insert(newGroupRegionName);
|
||||
|
||||
return *groupRegionNameItr;
|
||||
}
|
||||
|
||||
void CpuProfilerImpl::OnSystemTick()
|
||||
{
|
||||
if (!m_enabled)
|
||||
|
||||
Reference in New Issue
Block a user