Remove statistics profiler

Signed-off-by: Jeremy Ong <jcong@amazon.com>
monroegm-disable-blank-issue-2
Jeremy Ong 5 years ago
parent df9b4d4a2f
commit a5f072f7a9

@ -13,9 +13,6 @@
#ifdef USE_PIX
#include <AzCore/PlatformIncl.h>
#include <WinPixEventRuntime/pix3.h>
// The pix3 header unfortunately brings in other Windows macros we need to undef
#undef DeleteFile
#undef LoadImage
#endif
#ifdef AZ_PROFILE_TELEMETRY
@ -32,11 +29,11 @@
* Macro to declare a profile section for the current scope { }.
* format is: AZ_PROFILE_SCOPE(categoryName, const char* formatStr, ...)
*/
# define AZ_PROFILE_SCOPE(category, formatStr, ...) ::AZ::ProfileScope AZ_JOIN(azProfileScope, __LINE__){ #category, formatStr, __VA_ARGS__ }
# define AZ_PROFILE_SCOPE(category, ...) ::AZ::ProfileScope AZ_JOIN(azProfileScope, __LINE__){ #category, __VA_ARGS__ }
# define AZ_PROFILE_FUNCTION(category) AZ_PROFILE_SCOPE(category, AZ_FUNCTION_SIGNATURE)
// Prefer using the scoped macros which automatically end the event (AZ_PROFILE_SCOPE/AZ_PROFILE_FUNCTION)
# define AZ_PROFILE_BEGIN(category, name, ...) ::AZ::ProfileScope::BeginRegion(#category, name, __VA_ARGS__)
# define AZ_PROFILE_BEGIN(category, ...) ::AZ::ProfileScope::BeginRegion(#category, __VA_ARGS__)
# define AZ_PROFILE_END() ::AZ::ProfileScope::EndRegion()
#endif // AZ_PROFILER_MACRO_DISABLE
@ -67,14 +64,11 @@ namespace AZ
static uint32_t GetSystemID(const char* system);
template<typename... T>
static void BeginRegion(const char* system, char const* eventName, [[maybe_unused]] T const&... args)
static void BeginRegion([[maybe_unused]] const char* system, [[maybe_unused]] char const* eventName, [[maybe_unused]] T const&... args)
{
// TODO: Verification that the supplied system name corresponds to a known budget
#if defined(USE_PIX)
PIXBeginEvent(PIX_COLOR_INDEX(GetSystemID(system) & 0xff), eventName, args...);
#else
(void)system;
(void)eventName;
#endif
// TODO: injecting instrumentation for other profilers
}
@ -395,3 +389,9 @@ namespace AZ
}
} // namespace AZ
#ifdef USE_PIX
// The pix3 header unfortunately brings in other Windows macros we need to undef
#undef DeleteFile
#undef LoadImage
#undef GetCurrentTime
#endif

@ -1,106 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "RunningStatisticsManager.h"
namespace AzFramework
{
namespace Statistics
{
bool RunningStatisticsManager::ContainsStatistic(const AZStd::string& name)
{
auto iterator = m_statisticsNamesToIndexMap.find(name);
return iterator != m_statisticsNamesToIndexMap.end();
}
bool RunningStatisticsManager::AddStatistic(const AZStd::string& name, const AZStd::string& units)
{
if (ContainsStatistic(name))
{
return false;
}
AddStatisticValidated(name, units);
return true;
}
void RunningStatisticsManager::RemoveStatistic(const AZStd::string& name)
{
auto iterator = m_statisticsNamesToIndexMap.find(name);
if (iterator == m_statisticsNamesToIndexMap.end())
{
return;
}
AZ::u32 itemIndex = iterator->second;
m_statistics.erase(m_statistics.begin() + itemIndex);
m_statisticsNamesToIndexMap.erase(iterator);
//Update the indices in m_statisticsNamesToIndexMap.
while (itemIndex < m_statistics.size())
{
const AZStd::string& statName = m_statistics[itemIndex].GetName();
m_statisticsNamesToIndexMap[statName] = itemIndex;
++itemIndex;
}
}
void RunningStatisticsManager::ResetStatistic(const AZStd::string& name)
{
NamedRunningStatistic* stat = GetStatistic(name);
if (!stat)
{
return;
}
stat->Reset();
}
void RunningStatisticsManager::ResetAllStatistics()
{
for (NamedRunningStatistic& stat : m_statistics)
{
stat.Reset();
}
}
void RunningStatisticsManager::PushSampleForStatistic(const AZStd::string& name, double value)
{
NamedRunningStatistic* stat = GetStatistic(name);
if (!stat)
{
return;
}
stat->PushSample(value);
}
NamedRunningStatistic* RunningStatisticsManager::GetStatistic(const AZStd::string& name, AZ::u32* indexOut)
{
auto iterator = m_statisticsNamesToIndexMap.find(name);
if (iterator == m_statisticsNamesToIndexMap.end())
{
return nullptr;
}
const AZ::u32 index = iterator->second;
if (indexOut)
{
*indexOut = index;
}
return &m_statistics[index];
}
const AZStd::vector<NamedRunningStatistic>& RunningStatisticsManager::GetAllStatistics() const
{
return m_statistics;
}
void RunningStatisticsManager::AddStatisticValidated(const AZStd::string& name, const AZStd::string& units)
{
m_statistics.emplace_back(NamedRunningStatistic(name, units));
const AZ::u32 itemIndex = static_cast<AZ::u32>(m_statistics.size() - 1);
m_statisticsNamesToIndexMap[name] = itemIndex;
}
}//namespace Statistics
}//namespace AzFramework

@ -1,255 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/BusImpl.h> //Just to get AZ::NullMutex
#include <AzCore/std/chrono/types.h>
#include <AzCore/Statistics/StatisticsManager.h>
#include <AzCore/std/parallel/scoped_lock.h>
namespace AZ
{
namespace Statistics
{
//! A helper class that facilitates collecting time spent in blocks (scopes) of code
//! and aggregating the measured times as running statistics.
//!
//! See "StatisticalProfilerProxy.h" for more explanations on the meaning of Statistical Profiling.
//!
//! The StatisticalProfiler was made as a template to accommodate for several performance needs...
//! If all the code that is being profiled is single threaded and you want to identify
//! each statistic by its string name, then the default StatisticalProfiler<> works for you.
//! If using a map<strings, stat> is too much of what you can afford, then index your
//! statistics with an integer or crc32 and your code profiler should be declared as
//! StatisticalProfiler<AZ::Crc32>.
//! For multi-threaded cases and indexing statistic with Crc32 you can have a profiler like this:
//! StatisticalProfiler<AZ::Crc32, AZStd::mutex>.
//! The UnitTests mentioned in the first paragraph do benchmarks of different combinations
//! of indexing and synchronization primitives.
//!
//! Even though you can create, subclass and use your own StatisticalProfiler<*,*>, there
//! are some things to consider when working with the StatisticalProfilerProxy:
//! The StatisticalProfilerProxy OWNS an array of StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>.
//! You can "manage" one of those StatisticalProfiler by getting a reference to it and
//! add Running statistics etc. See The TerrainProfilers mentioned above to see concrete use
//! cases on how to work with the StatisticalProfilerProxy.
template <class StatIdType = AZStd::string, class MutexType = AZ::NullMutex>
class StatisticalProfiler
{
public:
//! A Convenience class used to measure time performance of scopes of code
//! with constructor/destructor. Suitable to be used as part of a macro
//! to facilitate its usage.
class TimedScope
{
public:
TimedScope() = delete;
TimedScope(StatisticalProfiler& profiler, const StatIdType& statId)
: m_profiler(profiler), m_statId(statId)
{
m_startTime = AZStd::chrono::high_resolution_clock::now();
}
~TimedScope()
{
AZStd::chrono::system_clock::time_point stopTime = AZStd::chrono::high_resolution_clock::now();
AZStd::chrono::microseconds duration = stopTime - m_startTime;
m_profiler.PushSample(m_statId, static_cast<double>(duration.count()));
}
private:
StatisticalProfiler& m_profiler;
const StatIdType& m_statId;
AZStd::chrono::system_clock::time_point m_startTime;
}; //class TimedScope
friend class TimedScope;
StatisticalProfiler()
{
}
StatisticalProfiler(const StatisticalProfiler& other)
{
m_statisticsManager = other.m_statisticsManager;
m_statsVector.clear();
m_perFrameAggregates.clear();
}
StatisticalProfiler(StatisticalProfiler&& other)
{
m_statisticsManager = AZStd::move(other.m_statisticsManager);
m_perFrameAggregates = AZStd::move(other.m_perFrameAggregates);
}
virtual ~StatisticalProfiler()
{
}
AZ::Statistics::StatisticsManager<StatIdType>& GetStatsManager()
{
return m_statisticsManager;
}
//! Should be called once per frame, it runs over all existing timed stats in m_statsForPerFrameCalculation
//! and accumulates all the values as a single stat per frame.
double SummarizePerFrameStats()
{
AZStd::scoped_lock<MutexType> lock(m_mutex);
if (m_perFrameAggregates.size() < 1)
{
return 0.0;
}
double allStatsSumMicroSecs = 0.0;
for (StatisticalAggregate& aggregate : m_perFrameAggregates)
{
double statsSumMicroSecs = 0.0;
for (const AZ::Statistics::NamedRunningStatistic* stat : aggregate.m_statsForPerFrameCalculation)
{
statsSumMicroSecs += stat->GetSum();
}
const double frameTime = statsSumMicroSecs - aggregate.m_prevAccumulatedSums;
if (frameTime > 0.0)
{
aggregate.m_statPerFrame->PushSample(frameTime);
aggregate.m_prevAccumulatedSums = statsSumMicroSecs;
}
allStatsSumMicroSecs += statsSumMicroSecs;
}
return allStatsSumMicroSecs;
}
void LogAndResetStats(const char* windowName)
{
AZStd::scoped_lock<MutexType> lock(m_mutex);
if (m_statsVector.size() != m_statisticsManager.GetCount())
{
m_statsVector.clear();
m_statisticsManager.GetAllStatistics(m_statsVector);
}
for (AZ::Statistics::NamedRunningStatistic* stat : m_statsVector)
{
if (stat->GetNumSamples() == 0)
{
continue;
}
const AZStd::string& statReport = stat->GetFormatted();
AZ_Printf(windowName, "%s\n", statReport.c_str());
stat->Reset();
}
for (StatisticalAggregate& aggregate : m_perFrameAggregates)
{
aggregate.m_prevAccumulatedSums = 0.0;
}
}
void PushSample(const StatIdType& statId, double value)
{
AZStd::scoped_lock<MutexType> lock(m_mutex);
AZ::Statistics::NamedRunningStatistic* stat = m_statisticsManager.GetStatistic(statId);
if (!stat)
{
return;
}
stat->PushSample(value);
}
const AZ::Statistics::NamedRunningStatistic* GetStatistic(const StatIdType& statId)
{
return m_statisticsManager.GetStatistic(statId);
}
int AddPerFrameStatisticalAggregate(const AZStd::vector<StatIdType>& statIds,
const StatIdType& timePerFrameStatId,
const AZStd::string& timePerFrameStatName)
{
AZStd::scoped_lock<MutexType> lock(m_mutex);
m_perFrameAggregates.push_back(StatisticalAggregate());
StatisticalAggregate& aggregate = m_perFrameAggregates[m_perFrameAggregates.size() - 1];
int added_count = 0;
for (const StatIdType& statId : statIds)
{
AZ::Statistics::NamedRunningStatistic* stat = m_statisticsManager.GetStatistic(statId);
if (!stat)
{
continue;
}
auto const& itor = AZStd::find(aggregate.m_statsForPerFrameCalculation.begin(), aggregate.m_statsForPerFrameCalculation.end(), stat);
if (itor != aggregate.m_statsForPerFrameCalculation.end())
{
continue;
}
aggregate.m_statsForPerFrameCalculation.push_back(stat);
added_count++;
}
if (added_count < 1)
{
m_perFrameAggregates.pop_back();
return 0;
}
aggregate.m_statPerFrame = m_statisticsManager.AddStatistic(timePerFrameStatId, timePerFrameStatName, "us", true);
if (!aggregate.m_statPerFrame)
{
AZ_Warning("StatisticalProfiler", false, "Per frame stat with name %s already exists\n", timePerFrameStatName.c_str());
m_perFrameAggregates.pop_back();
return 0;
}
return added_count;
}
const AZ::Statistics::NamedRunningStatistic* GetFirstStatPerFrame() const
{
if (m_perFrameAggregates.size() < 1)
{
return nullptr;
}
return m_perFrameAggregates[0].m_statPerFrame;
}
protected:
//! Lock this before reading/writing to m_timeStatisticsManager, or else...
MutexType m_mutex;
AZ::Statistics::StatisticsManager<StatIdType> m_statisticsManager;
AZStd::vector<AZ::Statistics::NamedRunningStatistic*> m_statsVector;
struct StatisticalAggregate
{
StatisticalAggregate() : m_statPerFrame(nullptr), m_prevAccumulatedSums(0.0)
{
}
AZ::Statistics::NamedRunningStatistic* m_statPerFrame;
AZStd::vector<AZ::Statistics::NamedRunningStatistic*> m_statsForPerFrameCalculation;
//! This one is needed because running statistics are collected many times across
//! several frames. This value is used to calculate a per frame sample for @m_totalTimePerFrameStat,
//! by subtracting @m_prevAccumulatedSums from the accumulated sum in @m_statisticsManager.
double m_prevAccumulatedSums;
};
AZStd::vector<StatisticalAggregate> m_perFrameAggregates;
}; //class StatisticalProfiler
}; //namespace Statistics
}; //namespace AZ

@ -1,170 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/chrono/types.h>
#include <AzCore/std/parallel/shared_spin_mutex.h>
#include <AzCore/std/parallel/scoped_lock.h>
#include <AzCore/std/containers/bitset.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Statistics/StatisticalProfiler.h>
#include <AzCore/Debug/Profiler.h>
#if !defined(AZ_PROFILE_TELEMETRY) && defined(AZ_STATISTICAL_PROFILING_ENABLED)
#if defined(AZ_PROFILE_SCOPE)
#undef AZ_PROFILE_SCOPE
#endif // #if defined(AZ_PROFILE_SCOPE)
#define AZ_PROFILE_SCOPE(profiler, scopeNameId) \
static_assert(profiler < Count, "Invalid profiler category"); \
static const AZStd::string AZ_JOIN(blockName, __LINE__)(scopeNameId); \
AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(profiler, AZ_JOIN(blockName, __LINE__));
#endif //#if !defined(AZ_PROFILE_TELEMETRY)
namespace AZ
{
namespace Statistics
{
using StatisticalProfilerId = AZ::Name;
//! This AZ::Interface<> (Yes, it is an application wide singleton) owns an array of StatisticalProfilers.
//! When is this useful?
//! When you need to statistically profile code that runs across DLL boundaries.
//!
//! What is the meaning of "statistically profile" code?
//! In regular profiling with tools like RAD Telemetry, every execution of a profiled
//! scope of code will be captured when using AZ_PROFILE_SCOPE(). You can collect
//! very large amounts of data and do your own post processing and analysis in tools like Excel,etc.
//! In contrast, "statistical profiling" means that everytime AZ_PROFILE_SCOPE() is called,
//! the time spent in the given scope of code will be mathematically accumulated as part of a unique
//! Running statistic. Common statistical parameters like min, max, average, variance and standard deviation
//! are calculated on the fly. This approach reduces considerably the amount of data that is collected.
//! The data is recorded in the Game/Editor Log file.
//!
//! This StatisticalProfilerProxy should be used via the AZ_PROFILE_SCOPE() macro, and by using
//! this macro the developer gains the flexibility of switching at compile time between profiling
//! the code via RAD Telemetry or through statistical profiling.
//!
//! When creating a new statistical profiler add your category (aka profiler id) in Profiler.h (enum class ProfileCategory).
//! Get a reference of the statistical profiler with "GetProfiler(const StatisticalProfilerId& id)" using the profiler Id.
//! Once you get a reference to the profiler you can customize it, add Running statistics to it, etc.
//! Some class in your code will manage the reference to the statistical profiler and will determine
//! the policy on how often to log data to the game logs, etc. For example, by subclassing the TickBus Handler, etc.
//!
//! The StatisticalProfilerProxySystemComponent guarantees that the StatisticalProfilerProxy singleton exists
//! as soon as the AZ::Environment is fully initialized.
//! See StatisticalProfiler.h for more details and info.
class StatisticalProfilerProxy
{
public:
AZ_TYPE_INFO(StatisticalProfilerProxy, "{1103D0EB-1C32-4854-B9D9-40A2D65BDBD2}");
using StatIdType = AZStd::string;
using StatisticalProfilerType = StatisticalProfiler<StatIdType, AZStd::shared_spin_mutex>;
//! A Convenience class used to measure time performance of scopes of code
//! with constructor/destructor. Suitable to be used as part of a macro
//! to facilitate its usage.
class TimedScope
{
public:
TimedScope() = delete;
TimedScope(const StatisticalProfilerId profilerId, const StatIdType& statId)
: m_profilerId(profilerId), m_statId(statId)
{
if (!m_profilerProxy)
{
m_profilerProxy = AZ::Interface<StatisticalProfilerProxy>::Get();
if (!m_profilerProxy)
{
return;
}
}
if (!m_profilerProxy->IsProfilerActive(profilerId))
{
return;
}
m_startTime = AZStd::chrono::high_resolution_clock::now();
}
~TimedScope()
{
if (!m_profilerProxy)
{
return;
}
AZStd::chrono::system_clock::time_point stopTime = AZStd::chrono::high_resolution_clock::now();
AZStd::chrono::microseconds duration = stopTime - m_startTime;
m_profilerProxy->PushSample(m_profilerId, m_statId, static_cast<double>(duration.count()));
}
//! Required only for UnitTests
static void ClearCachedProxy()
{
m_profilerProxy = nullptr;
}
private:
static StatisticalProfilerProxy* m_profilerProxy;
const StatisticalProfilerId m_profilerId;
const StatIdType& m_statId;
AZStd::chrono::system_clock::time_point m_startTime;
}; //class TimedScope
friend class TimedScope;
StatisticalProfilerProxy()
{
m_profilers.reserve(static_cast<AZStd::size_t>(Count));
for (AZStd::size_t i = 0; i < static_cast<AZStd::size_t>(Count); i++)
{
m_profilers.emplace_back(StatisticalProfilerType());
}
AZ::Interface<StatisticalProfilerProxy>::Register(this);
}
virtual ~StatisticalProfilerProxy()
{
AZ::Interface<StatisticalProfilerProxy>::Unregister(this);
}
// Note that you have to delete these for safety reasons, you will trip a static_assert if you do not
StatisticalProfilerProxy(StatisticalProfilerProxy&&) = delete;
StatisticalProfilerProxy& operator=(StatisticalProfilerProxy&&) = delete;
bool IsProfilerActive(StatisticalProfilerId id) const
{
return m_activeProfilersFlag[static_cast<AZStd::size_t>(id)];
}
StatisticalProfilerType& GetProfiler(StatisticalProfilerId id)
{
return m_profilers[static_cast<AZStd::size_t>(id)];
}
void ActivateProfiler(StatisticalProfilerId id, bool activate)
{
m_activeProfilersFlag[static_cast<AZStd::size_t>(id)] = activate;
}
void PushSample(StatisticalProfilerId id, const StatIdType& statId, double value)
{
m_profilers[static_cast<AZStd::size_t>(id)].PushSample(statId, value);
}
private:
AZStd::bitset<static_cast<AZStd::size_t>(Count)> m_activeProfilersFlag;
AZStd::vector<StatisticalProfilerType> m_profilers;
}; //class StatisticalProfilerProxy
}; //namespace Statistics
}; //namespace AZ

@ -1,66 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include "StatisticalProfilerProxySystemComponent.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AZ
{
namespace Statistics
{
StatisticalProfilerProxy* StatisticalProfilerProxy::TimedScope::m_profilerProxy = nullptr;
////////////////////////////////////////////////////////////////////////////////////////////////
void StatisticalProfilerProxySystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<StatisticalProfilerProxySystemComponent, AZ::Component>()
->Version(1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
void StatisticalProfilerProxySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("StatisticalProfilerService", 0x20066f73));
}
////////////////////////////////////////////////////////////////////////////////////////////////
void StatisticalProfilerProxySystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("StatisticalProfilerService", 0x20066f73));
}
////////////////////////////////////////////////////////////////////////////////////////////////
StatisticalProfilerProxySystemComponent::StatisticalProfilerProxySystemComponent()
: m_StatisticalProfilerProxy(nullptr)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////
StatisticalProfilerProxySystemComponent::~StatisticalProfilerProxySystemComponent()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////
void StatisticalProfilerProxySystemComponent::Activate()
{
m_StatisticalProfilerProxy = new StatisticalProfilerProxy;
}
////////////////////////////////////////////////////////////////////////////////////////////////
void StatisticalProfilerProxySystemComponent::Deactivate()
{
delete m_StatisticalProfilerProxy;
}
} //namespace Statistics
} // namespace AZ

@ -1,67 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include "StatisticalProfilerProxy.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AZ
{
namespace Statistics
{
////////////////////////////////////////////////////////////////////////////////////////////////
//! This system component manages the globally unique StatisticalProfilerProxy instance.
//! And this is all this component does... it simply makes sure the StatisticalProfilerProxy exists.
class StatisticalProfilerProxySystemComponent : public AZ::Component
{
public:
////////////////////////////////////////////////////////////////////////////////////////////
// AZ::Component Setup
AZ_COMPONENT(StatisticalProfilerProxySystemComponent, "{1E15565F-A5C1-4BF2-8AEE-D3880AC9E1EB}")
////////////////////////////////////////////////////////////////////////////////////////////
//! \ref AZ::ComponentDescriptor::Reflect
static void Reflect(AZ::ReflectContext* reflection);
////////////////////////////////////////////////////////////////////////////////////////////
//! \ref AZ::ComponentDescriptor::GetProvidedServices
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
////////////////////////////////////////////////////////////////////////////////////////////
//! \ref AZ::ComponentDescriptor::GetIncompatibleServices
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
StatisticalProfilerProxySystemComponent();
////////////////////////////////////////////////////////////////////////////////////////////
//! Destructor
~StatisticalProfilerProxySystemComponent() override;
protected:
////////////////////////////////////////////////////////////////////////////////////////////
//! \ref AZ::Component::Activate
void Activate() override;
////////////////////////////////////////////////////////////////////////////////////////////
//! \ref AZ::Component::Deactivate
void Deactivate() override;
private:
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copy constructor
StatisticalProfilerProxySystemComponent(const StatisticalProfilerProxySystemComponent&) = delete;
////////////////////////////////////////////////////////////////////////////////////////////
// The one and only StatisticalProfilerProxy (Which is itself an AZ::Interface<>)
StatisticalProfilerProxy* m_StatisticalProfilerProxy;
};
} //namespace Statistics
} // namespace AZ

@ -1,200 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include "NamedRunningStatistic.h"
namespace AZ
{
namespace Statistics
{
/**
* @brief A Collection of Running Statistics, addressable by a hashable
* class/primitive. e.g. AZ::Crc32, int, AZStd::string, etc.
*
*/
template <class StatIdType = AZStd::string>
class StatisticsManager
{
public:
StatisticsManager() = default;
StatisticsManager(const StatisticsManager& other)
{
m_statistics.reserve(other.m_statistics.size());
for (auto const& it : other.m_statistics)
{
const StatIdType& statId = it.first;
const NamedRunningStatistic* stat = it.second;
m_statistics[statId] = new NamedRunningStatistic(*stat);
}
}
virtual ~StatisticsManager()
{
Clear();
}
bool ContainsStatistic(const StatIdType& statId) const
{
auto iterator = m_statistics.find(statId);
return iterator != m_statistics.end();
}
AZ::u32 GetCount() const
{
return static_cast<AZ::u32>(m_statistics.size());
}
void GetAllStatistics(AZStd::vector<NamedRunningStatistic*>& vector)
{
for (auto const& it : m_statistics)
{
NamedRunningStatistic* stat = it.second;
vector.push_back(stat);
}
}
//! Helper method to apply units to statistics with empty units string.
AZ::u32 ApplyUnits(const AZStd::string& units)
{
AZ::u32 updatedCount = 0;
for (auto& it : m_statistics)
{
NamedRunningStatistic* stat = it.second;
if (stat->GetUnits().empty())
{
stat->UpdateUnits(units);
updatedCount++;
}
}
return updatedCount;
}
void Clear()
{
for (auto& it : m_statistics)
{
NamedRunningStatistic* stat = it.second;
delete stat;
}
m_statistics.clear();
}
/**
* Returns nullptr if a statistic with such name doesn't exist,
* otherwise returns a pointer to the statistic.
*/
NamedRunningStatistic* GetStatistic(const StatIdType& statId)
{
auto iterator = m_statistics.find(statId);
if (iterator == m_statistics.end())
{
return nullptr;
}
return iterator->second;
}
//! Returns false if a NamedRunningStatistic with such id already exists.
NamedRunningStatistic* AddStatistic(const StatIdType& statId, const bool failIfExist = true)
{
if (failIfExist)
{
NamedRunningStatistic* prevStat = GetStatistic(statId);
if (prevStat)
{
return nullptr;
}
}
NamedRunningStatistic* stat = new NamedRunningStatistic();
m_statistics[statId] = stat;
return stat;
}
//! Returns false if a NamedRunningStatistic with such id already exists.
NamedRunningStatistic* AddStatistic(const StatIdType& statId, const AZStd::string& name, const AZStd::string& units, const bool failIfExist = true)
{
if (failIfExist)
{
NamedRunningStatistic* prevStat = GetStatistic(statId);
if (prevStat)
{
return nullptr;
}
}
NamedRunningStatistic* stat = new NamedRunningStatistic(name, units);
m_statistics[statId] = stat;
return stat;
}
virtual void RemoveStatistic(const StatIdType& statId)
{
auto iterator = m_statistics.find(statId);
if (iterator == m_statistics.end())
{
return;
}
NamedRunningStatistic* prevStat = iterator->second;
delete prevStat;
m_statistics.erase(iterator);
}
void ResetStatistic(const StatIdType& statId)
{
NamedRunningStatistic* stat = GetStatistic(statId);
if (!stat)
{
return;
}
stat->Reset();
}
void ResetAllStatistics()
{
for (auto& it : m_statistics)
{
NamedRunningStatistic* stat = it.second;
stat->Reset();
}
}
void PushSampleForStatistic(const StatIdType& statId, double value)
{
NamedRunningStatistic* stat = GetStatistic(statId);
if (!stat)
{
return;
}
stat->PushSample(value);
}
//! Expensive function because it does a reverse lookup
bool GetStatId(NamedRunningStatistic* searchStat, StatIdType& statIdOut) const
{
for (auto& it : m_statistics)
{
NamedRunningStatistic* stat = it.second;
if (stat == searchStat)
{
statIdOut = it.first;
return true;
}
}
return false;
}
private:
///Key: StatIdType, Value: NamedRunningStatistic*
AZStd::unordered_map<StatIdType, NamedRunningStatistic*> m_statistics;
};//class StatisticsManager
}//namespace Statistics
}//namespace AZ

@ -1,49 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "TimeDataStatisticsManager.h"
namespace AZ
{
namespace Statistics
{
void TimeDataStatisticsManager::PushTimeDataSample(const char * registerName, const AZ::Debug::ProfilerRegister::TimeData& timeData)
{
const AZStd::string statName(registerName);
NamedRunningStatistic* statistic = GetStatistic(statName);
if (!statistic)
{
const AZStd::string units("us");
AddStatistic(statName, statName, units, false);
AZ::Debug::ProfilerRegister::TimeData zeroTimeData;
memset(&zeroTimeData, 0, sizeof(AZ::Debug::ProfilerRegister::TimeData));
m_previousTimeData[statName] = zeroTimeData;
statistic = GetStatistic(statName);
AZ_Assert(statistic != nullptr, "Fatal error adding a new statistic object");
}
const AZ::u64 accumulatedTime = timeData.m_time;
const AZ::s64 totalNumCalls = timeData.m_calls;
const AZ::u64 previousAccumulatedTime = m_previousTimeData[statName].m_time;
const AZ::s64 previousTotalNumCalls = m_previousTimeData[statName].m_calls;
const AZ::u64 deltaTime = accumulatedTime - previousAccumulatedTime;
const AZ::s64 deltaCalls = totalNumCalls - previousTotalNumCalls;
if (deltaCalls == 0)
{
//This is the same old data. Let's skip it
return;
}
double newSample = static_cast<double>(deltaTime) / deltaCalls;
statistic->PushSample(newSample);
m_previousTimeData[statName] = timeData;
}
} //namespace Statistics
} //namespace AZ

@ -1,51 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Statistics/StatisticsManager.h>
namespace AZ
{
namespace Statistics
{
/**
* @brief Specialization useful for data generated with AZ::Debug::FrameProfileComponent
*
* Timer based data collection using AZ_PROFILE_SCOPE(...), available in
* AzCore/Debug/Profiler.h can be collected when using AZ::Debug::FrameProfilerComponent
* and AZ::Debug::FrameProfilerBus. The method PushTimeDataSample(...) is a convenience
* to convert those Timer registers into a RunningStatistic.
*
*
*/
class TimeDataStatisticsManager : public StatisticsManager<>
{
public:
TimeDataStatisticsManager() = default;
virtual ~TimeDataStatisticsManager() = default;
/**
* @brief Adds one sample data to a specific running stat by name.
*
* This method is specialized to work with ProfilerRegister::TimeData that can be intercepted
* during AZ::Debug::FrameProfilerBus::OnFrameProfilerData().
* For each @param registerName a new RunningStat object is created if it doesn't exist.
*
* Adds the TimeData as one sample for its RunningStatistic.
*/
void PushTimeDataSample(const char * registerName, const AZ::Debug::ProfilerRegister::TimeData& timeData);
protected:
///We store here the previous value from the previous timer frame data.
///This is necessary because AZ_PROFILER_TIMER is cumulative
///and we need the time spent for each call.
AZStd::unordered_map<AZStd::string, AZ::Debug::ProfilerRegister::TimeData> m_previousTimeData;
};
} //namespace Statistics
} //namespace AZ

@ -566,9 +566,6 @@ set(FILES
Statistics/NamedRunningStatistic.h
Statistics/RunningStatistic.cpp
Statistics/RunningStatistic.h
Statistics/StatisticsManager.h
Statistics/TimeDataStatisticsManager.cpp
Statistics/TimeDataStatisticsManager.h
StringFunc/StringFunc.cpp
StringFunc/StringFunc.h
UserSettings/UserSettings.cpp

@ -1255,7 +1255,7 @@ namespace UnitTest
int ChildFunction1(int input)
{
AZ_PROFILE_SCOPE(System, "Child1");
AZ_PROFILE_SCOPE(AzCore, "Child1");
int result = 5;
for (int i = 0; i < 10000; ++i)
{
@ -1266,7 +1266,7 @@ namespace UnitTest
int Profile1(int numIterations)
{
AZ_PROFILE_SCOPE(System, "Custom name");
AZ_PROFILE_SCOPE(AzCore, "Custom name");
int result = 0;
for (int i = 0; i < numIterations; ++i)
{

@ -6,16 +6,16 @@
*
*/
#include <AzCore/Math/Obb.h>
#include <AZTestShared/Math/MathTestHelpers.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Obb.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AZTestShared/Math/MathTestHelpers.h>
using namespace AZ;
namespace UnitTest
namespace UnitTest::ObbTests
{
const Vector3 position(1.0f, 2.0f, 3.0f);
const Quaternion rotation = Quaternion::CreateRotationZ(Constants::QuarterPi);
@ -151,4 +151,4 @@ namespace UnitTest
EXPECT_NEAR(obb.GetDistanceSq(Vector3(2.4f, 0.5f, 1.5f)), 0.5532f, 1e-3f);
EXPECT_NEAR(obb.GetDistanceSq(Vector3(1.1f, 7.3f, 5.8f)), 1.3612f, 1e-3f);
}
}
} // namespace UnitTest::ObbTests

@ -1,847 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/UnitTest/UnitTest.h>
#include <AzTest/AzTest.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/parallel/thread.h>
#include <AzCore/std/parallel/shared_spin_mutex.h>
#include <AzCore/Debug/TraceMessagesDrillerBus.h>
#include <AzCore/Statistics/StatisticalProfilerProxy.h>
//REMARK: The macros CODE_PROFILER_PROXY_PUSH_TIME and CODE_PROFILER_PUSH_TIME will be redefined
//several times in this file to accommodate for the different specializations of the StatisticalProfiler<>
//template.
#ifdef CODE_PROFILER_PROXY_PUSH_TIME
#undef CODE_PROFILER_PROXY_PUSH_TIME
#endif
#ifdef CODE_PROFILER_PUSH_TIME
#undef CODE_PROFILER_PUSH_TIME
#endif
namespace UnitTest
{
class StatisticalProfilerTest
: public AllocatorsFixture
{
public:
StatisticalProfilerTest()
{
}
void SetUp() override
{
AllocatorsFixture::SetUp();
}
~StatisticalProfilerTest()
{
}
void TearDown() override
{
AllocatorsFixture::TearDown();
}
}; //class StatisticalProfilerTest
TEST_F(StatisticalProfilerTest, StatisticalProfilerStringNoMutex_ProfileCode_ValidateStatistics)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<> profiler;
const AZStd::string statNamePerformance("PerformanceResult");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNamePerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNameBlock, statNameBlock, "us") != nullptr);
const int iter_count = 10;
{
CODE_PROFILER_PUSH_TIME(profiler, statNamePerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statNameBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statNamePerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNamePerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statNameBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNameBlock)->GetNumSamples(), iter_count);
#undef CODE_PROFILER_PUSH_TIME
}
TEST_F(StatisticalProfilerTest, StatisticalProfilerCrc32NoMutex_ProfileCode_ValidateStatistics)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<AZ::Crc32>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<AZ::Crc32> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
const int iter_count = 10;
{
CODE_PROFILER_PUSH_TIME(profiler, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statIdBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdPerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
#undef CODE_PROFILER_PUSH_TIME
}
TEST_F(StatisticalProfilerTest, StatisticalProfilerStringWithSharedSpinMutex__ProfileCode_ValidateStatistics)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex> profiler;
const AZStd::string statNamePerformance("PerformanceResult");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNamePerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNameBlock, statNameBlock, "us") != nullptr);
const int iter_count = 10;
{
CODE_PROFILER_PUSH_TIME(profiler, statNamePerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statNameBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statNamePerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNamePerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statNameBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNameBlock)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statNamePerformance) != nullptr);
#undef CODE_PROFILER_PUSH_TIME
}
TEST_F(StatisticalProfilerTest, StatisticalProfilerCrc32WithSharedSpinMutex__ProfileCode_ValidateStatistics)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<AZ::Crc32, AZStd::shared_spin_mutex>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<AZ::Crc32, AZStd::shared_spin_mutex> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
const int iter_count = 10;
{
CODE_PROFILER_PUSH_TIME(profiler, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statIdBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdPerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
#undef CODE_PROFILER_PUSH_TIME
}
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
static void simple_thread01(AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>* profiler, int loop_cnt)
{
const AZStd::string simple_thread("simple_thread1");
const AZStd::string simple_thread_loop("simple_thread1_loop");
CODE_PROFILER_PUSH_TIME(*profiler, simple_thread);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PUSH_TIME(*profiler, simple_thread_loop);
counter++;
}
}
static void simple_thread02(AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>* profiler, int loop_cnt)
{
const AZStd::string simple_thread("simple_thread2");
const AZStd::string simple_thread_loop("simple_thread2_loop");
CODE_PROFILER_PUSH_TIME(*profiler, simple_thread);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PUSH_TIME(*profiler, simple_thread_loop);
counter++;
}
}
static void simple_thread03(AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>* profiler, int loop_cnt)
{
const AZStd::string simple_thread("simple_thread3");
const AZStd::string simple_thread_loop("simple_thread3_loop");
CODE_PROFILER_PUSH_TIME(*profiler, simple_thread);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PUSH_TIME(*profiler, simple_thread_loop);
counter++;
}
}
#undef CODE_PROFILER_PUSH_TIME
TEST_F(StatisticalProfilerTest, StatisticalProfilerStringWithSharedSpinMutex_RunProfiledThreads_ValidateStatistics)
{
AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex> profiler;
const AZStd::string statIdThread1 = "simple_thread1";
const AZStd::string statNameThread1("simple_thread1");
const AZStd::string statIdThread1Loop = "simple_thread1_loop";
const AZStd::string statNameThread1Loop("simple_thread1_loop");
const AZStd::string statIdThread2 = "simple_thread2";
const AZStd::string statNameThread2("simple_thread2");
const AZStd::string statIdThread2Loop = "simple_thread2_loop";
const AZStd::string statNameThread2Loop("simple_thread2_loop");
const AZStd::string statIdThread3 = "simple_thread3";
const AZStd::string statNameThread3("simple_thread3");
const AZStd::string statIdThread3Loop = "simple_thread3_loop";
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1Loop, statNameThread1Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2, statNameThread2, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2Loop, statNameThread2Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 10;
AZStd::thread t1(AZStd::bind(&simple_thread01, &profiler, iter_count));
AZStd::thread t2(AZStd::bind(&simple_thread02, &profiler, iter_count));
AZStd::thread t3(AZStd::bind(&simple_thread03, &profiler, iter_count));
t1.join();
t2.join();
t3.join();
ASSERT_TRUE(profiler.GetStatistic(statIdThread1) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread1Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3Loop)->GetNumSamples(), iter_count);
}
TEST_F(StatisticalProfilerTest, StatisticalProfilerProxy_ProfileCode_ValidateStatistics)
{
#define CODE_PROFILER_PROXY_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(Terrain);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance = "PerformanceResult";
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock = "Block";
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
proxy->ActivateProfiler(Terrain, true);
const int iter_count = 10;
{
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, statIdBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdPerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
//Clean Up
proxy->ActivateProfiler(Terrain, false);
#undef CODE_PROFILER_PROXY_PUSH_TIME
}
#define CODE_PROFILER_PROXY_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
static void simple_thread1(int loop_cnt)
{
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread1("simple_thread1");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread1_loop("simple_thread1_loop");
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, simple_thread1);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, simple_thread1_loop);
counter++;
}
}
static void simple_thread2(int loop_cnt)
{
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread2("simple_thread2");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread2_loop("simple_thread2_loop");
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, simple_thread2);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, simple_thread2_loop);
counter++;
}
}
static void simple_thread3(int loop_cnt)
{
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread3("simple_thread3");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread3_loop("simple_thread3_loop");
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, simple_thread3);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, simple_thread3_loop);
}
}
#undef CODE_PROFILER_PROXY_PUSH_TIME
TEST_F(StatisticalProfilerTest, StatisticalProfilerProxy3_RunProfiledThreads_ValidateStatistics)
{
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(Terrain);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1 = "simple_thread1";
const AZStd::string statNameThread1("simple_thread1");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop = "simple_thread1_loop";
const AZStd::string statNameThread1Loop("simple_thread1_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2 = "simple_thread2";
const AZStd::string statNameThread2("simple_thread2");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop = "simple_thread2_loop";
const AZStd::string statNameThread2Loop("simple_thread2_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3 = "simple_thread3";
const AZStd::string statNameThread3("simple_thread3");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop = "simple_thread3_loop";
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1Loop, statNameThread1Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2, statNameThread2, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2Loop, statNameThread2Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
proxy->ActivateProfiler(Terrain, true);
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 10;
AZStd::thread t1(AZStd::bind(&simple_thread1, iter_count));
AZStd::thread t2(AZStd::bind(&simple_thread2, iter_count));
AZStd::thread t3(AZStd::bind(&simple_thread3, iter_count));
t1.join();
t2.join();
t3.join();
ASSERT_TRUE(profiler.GetStatistic(statIdThread1) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread1Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3Loop)->GetNumSamples(), iter_count);
//Clean Up
proxy->ActivateProfiler(Terrain, false);
}
/** Trace message handler to track messages during tests
*/
struct MyTraceMessageSink final
: public AZ::Debug::TraceMessageDrillerBus::Handler
{
MyTraceMessageSink()
{
AZ::Debug::TraceMessageDrillerBus::Handler::BusConnect();
}
~MyTraceMessageSink()
{
AZ::Debug::TraceMessageDrillerBus::Handler::BusDisconnect();
}
//////////////////////////////////////////////////////////////////////////
// TraceMessageDrillerBus
void OnPrintf(const char* window, const char* message) override
{
OnOutput(window, message);
}
void OnOutput(const char* window, const char* message) override
{
printf("%s: %s\n", window, message);
}
}; //struct MyTraceMessageSink
class Suite_StatisticalProfilerPerformance
: public AllocatorsFixture
{
public:
MyTraceMessageSink* m_testSink;
Suite_StatisticalProfilerPerformance() :m_testSink(nullptr)
{
}
void SetUp() override
{
AllocatorsFixture::SetUp();
m_testSink = new MyTraceMessageSink();
}
~Suite_StatisticalProfilerPerformance()
{
}
void TearDown() override
{
// clearing up memory
delete m_testSink;
AllocatorsFixture::TearDown();
}
}; //class Suite_StatisticalProfilerPerformance
TEST_F(Suite_StatisticalProfilerPerformance, StatisticalProfilerStringNoMutex_1ThreadPerformance)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<> profiler;
const AZStd::string statNamePerformance("PerformanceResult");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNamePerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNameBlock, statNameBlock, "us") != nullptr);
const int iter_count = 1000000;
{
CODE_PROFILER_PUSH_TIME(profiler, statNamePerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statNameBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statNamePerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNamePerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statNameBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNameBlock)->GetNumSamples(), iter_count);
profiler.LogAndResetStats("StatisticalProfilerStringNoMutex");
ASSERT_TRUE(profiler.GetStatistic(statNamePerformance) != nullptr);
#undef CODE_PROFILER_PUSH_TIME
}
TEST_F(Suite_StatisticalProfilerPerformance, StatisticalProfilerCrc32NoMutex_1ThreadPerformance)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<AZ::Crc32>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<AZ::Crc32> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
const int iter_count = 1000000;
{
CODE_PROFILER_PUSH_TIME(profiler, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statIdBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdPerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
profiler.LogAndResetStats("StatisticalProfilerCrc32NoMutex");
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
#undef CODE_PROFILER_PUSH_TIME
}
TEST_F(Suite_StatisticalProfilerPerformance, StatisticalProfilerStringWithSharedSpinMutex_1ThreadPerformance)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex> profiler;
const AZStd::string statNamePerformance("PerformanceResult");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNamePerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statNameBlock, statNameBlock, "us") != nullptr);
const int iter_count = 1000000;
{
CODE_PROFILER_PUSH_TIME(profiler, statNamePerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statNameBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statNamePerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNamePerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statNameBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statNameBlock)->GetNumSamples(), iter_count);
profiler.LogAndResetStats("StatisticalProfilerStringWithSharedSpinMutex");
ASSERT_TRUE(profiler.GetStatistic(statNamePerformance) != nullptr);
#undef CODE_PROFILER_PUSH_TIME
}
TEST_F(Suite_StatisticalProfilerPerformance, StatisticalProfilerCrc32WithSharedSpinMutex_1ThreadPerformance)
{
//Helper macro.
#define CODE_PROFILER_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfiler<AZ::Crc32, AZStd::shared_spin_mutex>::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
AZ::Statistics::StatisticalProfiler<AZ::Crc32, AZStd::shared_spin_mutex> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
const int iter_count = 1000000;
{
CODE_PROFILER_PUSH_TIME(profiler, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PUSH_TIME(profiler, statIdBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdPerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
profiler.LogAndResetStats("StatisticalProfilerCrc32WithSharedSpinMutex");
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
#undef CODE_PROFILER_PUSH_TIME
}
TEST_F(Suite_StatisticalProfilerPerformance, StatisticalProfilerStringWithSharedSpinMutex3Threads_3ThreadsPerformance)
{
AZ::Statistics::StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex> profiler;
const AZStd::string statIdThread1 = "simple_thread1";
const AZStd::string statNameThread1("simple_thread1");
const AZStd::string statIdThread1Loop = "simple_thread1_loop";
const AZStd::string statNameThread1Loop("simple_thread1_loop");
const AZStd::string statIdThread2 = "simple_thread2";
const AZStd::string statNameThread2("simple_thread2");
const AZStd::string statIdThread2Loop = "simple_thread2_loop";
const AZStd::string statNameThread2Loop("simple_thread2_loop");
const AZStd::string statIdThread3 = "simple_thread3";
const AZStd::string statNameThread3("simple_thread3");
const AZStd::string statIdThread3Loop = "simple_thread3_loop";
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1Loop, statNameThread1Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2, statNameThread2, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2Loop, statNameThread2Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 1000000;
AZStd::thread t1(AZStd::bind(&simple_thread01, &profiler, iter_count));
AZStd::thread t2(AZStd::bind(&simple_thread02, &profiler, iter_count));
AZStd::thread t3(AZStd::bind(&simple_thread03, &profiler, iter_count));
t1.join();
t2.join();
t3.join();
ASSERT_TRUE(profiler.GetStatistic(statIdThread1) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread1Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3Loop)->GetNumSamples(), iter_count);
profiler.LogAndResetStats("3_Threads_StatisticalProfiler");
ASSERT_TRUE(profiler.GetStatistic(statIdThread1) != nullptr);
}
#define CODE_PROFILER_PROXY_PUSH_TIME(profiler, scopeNameId) \
AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(profiler, scopeNameId);
TEST_F(Suite_StatisticalProfilerPerformance, StatisticalProfilerProxy_1ThreadPerformance)
{
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(Terrain);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance = "PerformanceResult";
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock = "Block";
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
proxy->ActivateProfiler(Terrain, true);
const int iter_count = 1000000;
{
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(Terrain, statIdBlock)
counter++;
}
}
ASSERT_TRUE(profiler.GetStatistic(statIdPerformance) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdPerformance)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdBlock) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
profiler.LogAndResetStats("StatisticalProfilerProxy");
//Clean Up
proxy->ActivateProfiler(Terrain, false);
}
#undef CODE_PROFILER_PROXY_PUSH_TIME
TEST_F(Suite_StatisticalProfilerPerformance, StatisticalProfilerProxy_3ThreadsPerformance)
{
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(Terrain);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1 = "simple_thread1";
const AZStd::string statNameThread1("simple_thread1");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop = "simple_thread1_loop";
const AZStd::string statNameThread1Loop("simple_thread1_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2 = "simple_thread2";
const AZStd::string statNameThread2("simple_thread2");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop = "simple_thread2_loop";
const AZStd::string statNameThread2Loop("simple_thread2_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3 = "simple_thread3";
const AZStd::string statNameThread3("simple_thread3");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop = "simple_thread3_loop";
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1Loop, statNameThread1Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2, statNameThread2, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread2Loop, statNameThread2Loop, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
proxy->ActivateProfiler(Terrain, true);
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 1000000;
AZStd::thread t1(AZStd::bind(&simple_thread1, iter_count));
AZStd::thread t2(AZStd::bind(&simple_thread2, iter_count));
AZStd::thread t3(AZStd::bind(&simple_thread3, iter_count));
t1.join();
t2.join();
t3.join();
ASSERT_TRUE(profiler.GetStatistic(statIdThread1) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread1Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread1Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread2Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread2Loop)->GetNumSamples(), iter_count);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3)->GetNumSamples(), 1);
ASSERT_TRUE(profiler.GetStatistic(statIdThread3Loop) != nullptr);
EXPECT_EQ(profiler.GetStatistic(statIdThread3Loop)->GetNumSamples(), iter_count);
profiler.LogAndResetStats("3_Threads_StatisticalProfilerProxy");
//Clean Up
proxy->ActivateProfiler(Terrain, false);
}
}//namespace UnitTest

@ -1,263 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/UnitTest/UnitTest.h>
#include <AzTest/AzTest.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Statistics/StatisticsManager.h>
using namespace AZ;
using namespace Debug;
namespace UnitTest
{
class StatisticsTest
: public AllocatorsFixture
{
public:
StatisticsTest()
{
}
void SetUp() override
{
AllocatorsFixture::SetUp();
m_dataSamples = AZStd::make_unique<AZStd::vector<u32>>();
const u32 numSamples = 100;
m_dataSamples->set_capacity(numSamples);
for (u32 i = 0; i < numSamples; ++i)
{
m_dataSamples->push_back(i);
}
}
~StatisticsTest()
{
}
void TearDown() override
{
// clearing up memory
m_dataSamples = nullptr;
AllocatorsFixture::TearDown();
}
protected:
AZStd::unique_ptr<AZStd::vector<u32>> m_dataSamples;
}; //class StatisticsTest
TEST_F(StatisticsTest, RunningStatistic_ProcessAnArrayOfNumbers_GetExpectedStatisticalData)
{
Statistics::RunningStatistic runningStat;
ASSERT_TRUE(m_dataSamples.get() != nullptr);
const AZStd::vector<u32>& dataSamples = *m_dataSamples;
for (u32 sample : dataSamples)
{
runningStat.PushSample(sample);
}
EXPECT_EQ(runningStat.GetNumSamples(), dataSamples.size());
EXPECT_EQ(runningStat.GetMostRecentSample(), dataSamples.back());
EXPECT_EQ(runningStat.GetMinimum(), dataSamples[0]);
EXPECT_EQ(runningStat.GetMaximum(), dataSamples.back());
EXPECT_NEAR(runningStat.GetAverage(), 49.5, 0.001);
EXPECT_NEAR(runningStat.GetVariance(), 841.666, 0.001);
EXPECT_NEAR(runningStat.GetStdev(), 29.011, 0.001);
EXPECT_NEAR(runningStat.GetVariance(Statistics::VarianceType::P), 833.25, 0.001);
EXPECT_NEAR(runningStat.GetStdev(Statistics::VarianceType::P), 28.866, 0.001);
//Reset the stat object.
runningStat.Reset();
EXPECT_EQ(runningStat.GetNumSamples(), 0);
EXPECT_EQ(runningStat.GetAverage(), 0.0);
EXPECT_EQ(runningStat.GetStdev(), 0.0);
}
TEST_F(StatisticsTest, StatisticsManager_AddAndRemoveStatisticistics_CollectionIntegrityIsCorrect)
{
Statistics::StatisticsManager<> statsManager;
AZStd::string statName0("stat0");
AZStd::string statName1("stat1");
AZStd::string statName2("stat2");
AZStd::string statName3("stat3");
EXPECT_TRUE(statsManager.AddStatistic(statName0, statName0, ""));
EXPECT_TRUE(statsManager.AddStatistic(statName1, statName1, ""));
EXPECT_TRUE(statsManager.AddStatistic(statName2, statName2, ""));
EXPECT_TRUE(statsManager.AddStatistic(statName3, statName3, ""));
//Validate the number of running statistics object we have so far.
{
AZStd::vector<Statistics::NamedRunningStatistic*> allStats;
statsManager.GetAllStatistics(allStats);
EXPECT_TRUE(allStats.size() == 4);
}
//Try to add an Stat that already exist. expect to fail.
EXPECT_EQ(statsManager.AddStatistic(statName1), nullptr);
//Remove stat1.
statsManager.RemoveStatistic(statName1);
//Validate the number of running statistics object we have so far.
{
AZStd::vector<Statistics::NamedRunningStatistic*> allStats;
statsManager.GetAllStatistics(allStats);
EXPECT_TRUE(allStats.size() == 3);
}
//Add stat1 again, expect to pass.
EXPECT_TRUE(statsManager.AddStatistic(statName1));
//Get a pointer to stat2.
Statistics::NamedRunningStatistic* stat2 = statsManager.GetStatistic(statName2);
ASSERT_TRUE(stat2 != nullptr);
EXPECT_EQ(stat2->GetName(), statName2);
}
TEST_F(StatisticsTest, StatisticsManager_DistributeSamplesAcrossStatistics_StatisticsAreCorrect)
{
Statistics::StatisticsManager<> statsManager;
AZStd::string statName0("stat0");
AZStd::string statName1("stat1");
AZStd::string statName2("stat2");
AZStd::string statName3("stat3");
EXPECT_TRUE(statsManager.AddStatistic(statName3));
EXPECT_TRUE(statsManager.AddStatistic(statName0));
EXPECT_TRUE(statsManager.AddStatistic(statName2));
EXPECT_TRUE(statsManager.AddStatistic(statName1));
//Distribute the 100 samples of data evenly across the 4 running statistics.
ASSERT_TRUE(m_dataSamples.get() != nullptr);
const AZStd::vector<u32>& dataSamples = *m_dataSamples;
const size_t numSamples = dataSamples.size();
const size_t numSamplesPerStat = numSamples / 4;
size_t sampleIndex = 0;
size_t nextStopIndex = numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName0, dataSamples[sampleIndex]);
sampleIndex++;
}
nextStopIndex += numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName1, dataSamples[sampleIndex]);
sampleIndex++;
}
nextStopIndex += numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName2, dataSamples[sampleIndex]);
sampleIndex++;
}
nextStopIndex += numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName3, dataSamples[sampleIndex]);
sampleIndex++;
}
EXPECT_NEAR(statsManager.GetStatistic(statName0)->GetAverage(), 12.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName1)->GetAverage(), 37.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName2)->GetAverage(), 62.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName3)->GetAverage(), 87.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName0)->GetStdev(), 7.359, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName1)->GetStdev(), 7.359, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName2)->GetStdev(), 7.359, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName3)->GetStdev(), 7.359, 0.001);
//Reset one of the stats.
statsManager.ResetStatistic(statName2);
EXPECT_EQ(statsManager.GetStatistic(statName2)->GetAverage(), 0.0);
//Reset all of the stats.
statsManager.ResetAllStatistics();
EXPECT_EQ(statsManager.GetStatistic(statName0)->GetNumSamples(), 0);
EXPECT_EQ(statsManager.GetStatistic(statName1)->GetNumSamples(), 0);
EXPECT_EQ(statsManager.GetStatistic(statName2)->GetNumSamples(), 0);
EXPECT_EQ(statsManager.GetStatistic(statName3)->GetNumSamples(), 0);
}
TEST_F(StatisticsTest, StatisticsManagerCrc32_DistributeSamplesAcrossStatistics_StatisticsAreCorrect)
{
Statistics::StatisticsManager<AZ::Crc32> statsManager;
AZ::Crc32 statName0 = AZ_CRC("stat0", 0xb8927780);
AZ::Crc32 statName1 = AZ_CRC("stat1", 0xcf954716);
AZ::Crc32 statName2 = AZ_CRC("stat2", 0x569c16ac);
AZ::Crc32 statName3 = AZ_CRC("stat3", 0x219b263a);
EXPECT_TRUE(statsManager.AddStatistic(statName3) != nullptr);
EXPECT_TRUE(statsManager.AddStatistic(statName0) != nullptr);
EXPECT_TRUE(statsManager.AddStatistic(statName2) != nullptr);
EXPECT_TRUE(statsManager.AddStatistic(statName1) != nullptr);
EXPECT_TRUE(statsManager.GetStatistic(statName3) != nullptr);
EXPECT_TRUE(statsManager.GetStatistic(statName0) != nullptr);
EXPECT_TRUE(statsManager.GetStatistic(statName1) != nullptr);
EXPECT_TRUE(statsManager.GetStatistic(statName2) != nullptr);
//Distribute the 100 samples of data evenly across the 4 running statistics.
ASSERT_TRUE(m_dataSamples.get() != nullptr);
const AZStd::vector<u32>& dataSamples = *m_dataSamples;
const size_t numSamples = dataSamples.size();
const size_t numSamplesPerStat = numSamples / 4;
size_t sampleIndex = 0;
size_t nextStopIndex = numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName0, dataSamples[sampleIndex]);
sampleIndex++;
}
nextStopIndex += numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName1, dataSamples[sampleIndex]);
sampleIndex++;
}
nextStopIndex += numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName2, dataSamples[sampleIndex]);
sampleIndex++;
}
nextStopIndex += numSamplesPerStat;
while (sampleIndex < nextStopIndex)
{
statsManager.PushSampleForStatistic(statName3, dataSamples[sampleIndex]);
sampleIndex++;
}
EXPECT_NEAR(statsManager.GetStatistic(statName0)->GetAverage(), 12.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName1)->GetAverage(), 37.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName2)->GetAverage(), 62.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName3)->GetAverage(), 87.0, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName0)->GetStdev(), 7.359, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName1)->GetStdev(), 7.359, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName2)->GetStdev(), 7.359, 0.001);
EXPECT_NEAR(statsManager.GetStatistic(statName3)->GetStdev(), 7.359, 0.001);
//Reset one of the stats.
statsManager.ResetStatistic(statName2);
EXPECT_EQ(statsManager.GetStatistic(statName2)->GetAverage(), 0.0);
//Reset all of the stats.
statsManager.ResetAllStatistics();
EXPECT_EQ(statsManager.GetStatistic(statName0)->GetNumSamples(), 0);
EXPECT_EQ(statsManager.GetStatistic(statName1)->GetNumSamples(), 0);
EXPECT_EQ(statsManager.GetStatistic(statName2)->GetNumSamples(), 0);
EXPECT_EQ(statsManager.GetStatistic(statName3)->GetNumSamples(), 0);
}
}//namespace UnitTest

@ -1,207 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/UnitTest/UnitTest.h>
#include <AzTest/AzTest.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/parallel/thread.h>
#include <AzCore/Statistics/TimeDataStatisticsManager.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Component/EntityUtils.h>
#include <AzCore/Debug/FrameProfilerBus.h>
#include <AzCore/Debug/FrameProfilerComponent.h>
using namespace AZ;
using namespace Debug;
namespace UnitTest
{
/**
* Validate functionality of the convenience class TimeDataStatisticsManager.
* It is a specialized version of RunningStatisticsManager that works with Timer type
* of registers that can be captured with the FrameProfilerBus::OnFrameProfilerData()
*/
class TimeDataStatisticsManagerTest
: public AllocatorsFixture
, public FrameProfilerBus::Handler
{
static constexpr const char* PARENT_TIMER_STAT = "ParentStat";
static constexpr const char* CHILD_TIMER_STAT0 = "ChildStat0";
static constexpr const char* CHILD_TIMER_STAT1 = "ChildStat1";
public:
TimeDataStatisticsManagerTest()
: AllocatorsFixture()
{
}
void SetUp() override
{
AllocatorsFixture::SetUp();
m_statsManager = AZStd::make_unique<Statistics::TimeDataStatisticsManager>();
}
void TearDown() override
{
m_statsManager = nullptr;
AllocatorsFixture::TearDown();
}
//////////////////////////////////////////////////////////////////////////
// FrameProfilerBus
virtual void OnFrameProfilerData(const FrameProfiler::ThreadDataArray& data)
{
for (size_t iThread = 0; iThread < data.size(); ++iThread)
{
const FrameProfiler::ThreadData& td = data[iThread];
FrameProfiler::ThreadData::RegistersMap::const_iterator regIt = td.m_registers.begin();
for (; regIt != td.m_registers.end(); ++regIt)
{
const FrameProfiler::RegisterData& rd = regIt->second;
u32 unitTestCrc = AZ_CRC("UnitTest", 0x8089cea8);
if (unitTestCrc != rd.m_systemId)
{
continue; //Not for us.
}
ASSERT_EQ(ProfilerRegister::PRT_TIME, rd.m_type);
const FrameProfiler::FrameData& fd = rd.m_frames.back();
m_statsManager->PushTimeDataSample(rd.m_name, fd.m_timeData);
}
}
}
//////////////////////////////////////////////////////////////////////////
int ChildFunction0(int numIterations, int sleepTimeMilliseconds)
{
AZ_PROFILE_SCOPE(AzCore, CHILD_TIMER_STAT0);
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
int result = 5;
for (int i = 0; i < numIterations; ++i)
{
result += i % 3;
}
return result;
}
int ChildFunction1(int numIterations, int sleepTimeMilliseconds)
{
AZ_PROFILE_SCOPE(AzCore, CHILD_TIMER_STAT1);
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
int result = 5;
for (int i = 0; i < numIterations; ++i)
{
result += i % 3;
}
return result;
}
int ParentFunction(int numIterations, int sleepTimeMilliseconds)
{
AZ_PROFILE_SCOPE(AzCore, PARENT_TIMER_STAT);
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
int result = 0;
result += ChildFunction0(numIterations, sleepTimeMilliseconds);
result += ChildFunction1(numIterations, sleepTimeMilliseconds);
return result;
}
void run()
{
Debug::FrameProfilerBus::Handler::BusConnect();
ComponentApplication app;
ComponentApplication::Descriptor desc;
desc.m_useExistingAllocator = true;
desc.m_enableDrilling = false; // we already created a memory driller for the test (AllocatorsFixture)
ComponentApplication::StartupParameters startupParams;
startupParams.m_allocator = &AllocatorInstance<SystemAllocator>::Get();
Entity* systemEntity = app.Create(desc, startupParams);
systemEntity->CreateComponent<FrameProfilerComponent>();
systemEntity->Init();
systemEntity->Activate(); // start frame component
const int sleepTimeAllFuncsMillis = 1;
const int numIterations = 10;
for (int iterationCounter = 0; iterationCounter < numIterations; ++iterationCounter)
{
ParentFunction(numIterations, sleepTimeAllFuncsMillis);
//Collect all samples.
app.Tick();
}
//Verify we have three running stats.
{
AZStd::vector<Statistics::NamedRunningStatistic*> allStats;
m_statsManager->GetAllStatistics(allStats);
EXPECT_EQ(allStats.size(), 3);
}
AZStd::string parentStatName(PARENT_TIMER_STAT);
AZStd::string child0StatName(CHILD_TIMER_STAT0);
AZStd::string child1StatName(CHILD_TIMER_STAT1);
ASSERT_TRUE(m_statsManager->GetStatistic(parentStatName) != nullptr);
ASSERT_TRUE(m_statsManager->GetStatistic(child0StatName) != nullptr);
ASSERT_TRUE(m_statsManager->GetStatistic(child1StatName) != nullptr);
EXPECT_EQ(m_statsManager->GetStatistic(parentStatName)->GetNumSamples(), numIterations);
EXPECT_EQ(m_statsManager->GetStatistic(child0StatName)->GetNumSamples(), numIterations);
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName)->GetNumSamples(), numIterations);
const double minimumExpectDurationOfChildFunctionMicros = 1;
const double minimumExpectDurationOfParentFunctionMicros = 1;
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetMinimum(), minimumExpectDurationOfParentFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetAverage(), minimumExpectDurationOfParentFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetMaximum(), minimumExpectDurationOfParentFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetMinimum(), minimumExpectDurationOfChildFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetAverage(), minimumExpectDurationOfChildFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetMaximum(), minimumExpectDurationOfChildFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetMinimum(), minimumExpectDurationOfChildFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetAverage(), minimumExpectDurationOfChildFunctionMicros);
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetMaximum(), minimumExpectDurationOfChildFunctionMicros);
//Let's validate TimeDataStatisticsManager::RemoveStatistics()
m_statsManager->RemoveStatistic(child1StatName);
ASSERT_TRUE(m_statsManager->GetStatistic(parentStatName) != nullptr);
ASSERT_TRUE(m_statsManager->GetStatistic(child0StatName) != nullptr);
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName), nullptr);
//Let's store the sample count for both parentStatName and child0StatName.
const AZ::u64 numSamplesParent = m_statsManager->GetStatistic(parentStatName)->GetNumSamples();
const AZ::u64 numSamplesChild0 = m_statsManager->GetStatistic(child0StatName)->GetNumSamples();
//Let's call child1 function again and call app.Tick(). child1StatName should be readded to m_statsManager.
ChildFunction1(numIterations, sleepTimeAllFuncsMillis);
app.Tick();
ASSERT_TRUE(m_statsManager->GetStatistic(child1StatName) != nullptr);
EXPECT_EQ(m_statsManager->GetStatistic(parentStatName)->GetNumSamples(), numSamplesParent);
EXPECT_EQ(m_statsManager->GetStatistic(child0StatName)->GetNumSamples(), numSamplesChild0);
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName)->GetNumSamples(), 1);
Debug::FrameProfilerBus::Handler::BusDisconnect();
app.Destroy();
}
AZStd::unique_ptr<Statistics::TimeDataStatisticsManager> m_statsManager;
};//class TimeDataStatisticsManagerTest
TEST_F(TimeDataStatisticsManagerTest, Test)
{
run();
}
//End of all Tests of TimeDataStatisticsManagerTest
}//namespace UnitTest

@ -60,13 +60,11 @@ set(FILES
SerializeContextFixture.h
Slice.cpp
State.cpp
Statistics.cpp
StreamerTests.cpp
StringFunc.cpp
SystemFile.cpp
TaskTests.cpp
TickBusTest.cpp
TimeDataStatistics.cpp
UUIDTests.cpp
XML.cpp
Debug/AssetTracking.cpp

@ -10,7 +10,6 @@
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
set(LY_STATISTICAL_PROFILING_ENABLED OFF CACHE BOOL "Enables statistical profiling when using AZ_PROFILE_SCOPE. If True, it takes effect only if RAD Telemetry is disabled.")
set(LY_TOUCHBENDING_LAYER_BIT 63 CACHE STRING "Use TouchBending as the collision layer. The TouchBending layer can be a number from 1 to 63 (Default=63).")
ly_add_target(
@ -38,14 +37,6 @@ ly_add_target(
3rdParty::lz4
)
if(LY_STATISTICAL_PROFILING_ENABLED)
ly_add_source_properties(
SOURCES AzFramework/Debug/StatisticalProfilerProxy.h
PROPERTY COMPILE_DEFINITIONS
VALUES AZ_STATISTICAL_PROFILING_ENABLED
)
endif()
ly_add_source_properties(
SOURCES
AzFramework/Physics/Collision/CollisionGroups.cpp

@ -700,7 +700,7 @@ namespace GridMate
{
if (IsUsingFixedTimeStep())
{
return static_cast<AZ::u32>(m_fixedTimeStep.CurrentTime());
return static_cast<AZ::u32>(m_fixedTimeStep.GetCurrentTime());
}
else
{

@ -302,7 +302,7 @@ namespace GridMate
// this could allow for changing on the fly but it would need to ensure that if it were in the middle of a second, that the new rate would result in landing on the
}
AZ::u64 CurrentTime() const
AZ::u64 GetCurrentTime() const
{
return m_currentTime;
}

@ -73,4 +73,3 @@ namespace ImageProcessingAtom
using ImageBuilderRequestBus = AZ::EBus<ImageBuilderRequests>;
} // namespace ImageProcessingAtom

@ -295,7 +295,7 @@ namespace AZ
void DecalTextureArrayFeatureProcessor::SetDecalMaterial(const DecalHandle handle, const AZ::Data::AssetId material)
{
AZ_PROFILE_FUNCTION(Renderer);
AZ_PROFILE_FUNCTION(AzRender);
if (handle.IsNull())
{
AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalMaterial().");
@ -365,7 +365,7 @@ namespace AZ
void DecalTextureArrayFeatureProcessor::OnAssetReady(const Data::Asset<Data::AssetData> asset)
{
AZ_PROFILE_FUNCTION(Renderer);
AZ_PROFILE_FUNCTION(AzRender);
const Data::AssetId& assetId = asset->GetId();
const RPI::MaterialAsset* materialAsset = asset.GetAs<AZ::RPI::MaterialAsset>();

@ -21,6 +21,7 @@
#include <Atom/RPI.Public/View.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Jobs/JobEmpty.h>
@ -541,6 +542,7 @@ namespace AZ
{
view->FinalizeDrawLists();
}
AZ_PROFILE_END();
}
else
{

@ -20,6 +20,9 @@
#include <EMotionFX/Source/EventInfo.h>
#include <EMotionFX/Source/MotionInstancePool.h>
#if defined GetCurrentTime
#undef GetCurrentTime
#endif
namespace EMotionFX
{

@ -12,7 +12,7 @@
#include <LZ4Compressor.h>
#include <AzCore/Compression/Compression.h>
#include <AzCore/std/time.h>
#include <AzCore/std/chrono/clocks.h>
#include <AzNetworking/DataStructures/ByteBuffer.h>
#include <AzNetworking/Serialization/NetworkInputSerializer.h>
#include <AzTest/AzTest.h>

@ -116,7 +116,7 @@ namespace NvCloth
}
void zoneEnd([[maybe_unused]] void* profilerData,
const char* eventName, bool detached,
[[maybe_unused]] const char* eventName, bool detached,
[[maybe_unused]] uint64_t contextId) override
{
if (detached)

@ -57,7 +57,7 @@ namespace ScriptCanvasEditor::Nodes
// Handles the creation of a node through the node configurations for most nodes.
AZ::EntityId DisplayGeneralScriptCanvasNode(AZ::EntityId, const ScriptCanvas::Node* node, const NodeConfiguration& nodeConfiguration)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
AZ::Entity* graphCanvasEntity = nullptr;
@ -445,7 +445,7 @@ namespace ScriptCanvasEditor::Nodes
AZ::EntityId DisplayEbusEventNode(AZ::EntityId, const AZStd::string& busName, const AZStd::string& eventName, const ScriptCanvas::EBusEventId& eventId)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
AZ::EntityId graphCanvasNodeId;
@ -668,7 +668,7 @@ namespace ScriptCanvasEditor::Nodes
AZ::EntityId DisplayScriptEventNode(AZ::EntityId, const AZ::Data::AssetId assetId, const ScriptEvents::Method& methodDefinition)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
AZ::EntityId graphCanvasNodeId;
@ -1001,7 +1001,7 @@ namespace ScriptCanvasEditor::Nodes
AZ::EntityId DisplayGetVariableNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::GetVariableNode* variableNode)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
NodeConfiguration nodeConfiguration;
nodeConfiguration.PopulateComponentDescriptors<IconComponent, DynamicSlotComponent, GetVariableNodeDescriptorComponent>();
@ -1033,7 +1033,7 @@ namespace ScriptCanvasEditor::Nodes
AZ::EntityId DisplaySetVariableNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::SetVariableNode* variableNode)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
NodeConfiguration nodeConfiguration;
nodeConfiguration.PopulateComponentDescriptors<IconComponent, DynamicSlotComponent, SetVariableNodeDescriptorComponent>();
@ -1069,7 +1069,7 @@ namespace ScriptCanvasEditor::Nodes
///////////////////
AZ::EntityId DisplayScriptCanvasNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Node* node)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
AZ::EntityId graphCanvasNodeId;
if (azrtti_istypeof<ScriptCanvas::Nodes::Core::SetVariableNode>(node))
@ -1122,7 +1122,7 @@ namespace ScriptCanvasEditor::Nodes
static void RegisterAndActivateGraphCanvasSlot(AZ::EntityId graphCanvasNodeId, const ScriptCanvas::SlotId& slotId, AZ::Entity* slotEntity)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
if (slotEntity)
{
slotEntity->Init();
@ -1166,7 +1166,7 @@ namespace ScriptCanvasEditor::Nodes
return AZ::EntityId();
}
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
AZ::Entity* slotEntity = nullptr;
AZ::Uuid typeId = ScriptCanvas::Data::ToAZType(slot.GetDataType());
@ -1258,7 +1258,7 @@ namespace ScriptCanvasEditor::Nodes::SlotDisplayHelper
{
AZ::EntityId DisplayPropertySlot(AZ::EntityId graphCanvasNodeId, const ScriptCanvas::VisualExtensionSlotConfiguration& propertyConfiguration)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
GraphCanvas::SlotConfiguration graphCanvasConfiguration;
@ -1284,7 +1284,7 @@ namespace ScriptCanvasEditor::Nodes::SlotDisplayHelper
AZ::EntityId DisplayExtendableSlot(AZ::EntityId graphCanvasNodeId, const ScriptCanvas::VisualExtensionSlotConfiguration& extenderConfiguration)
{
AZ_PROFILE_SCOPE("ScriptCanvas", __FUNCTION__);
AZ_PROFILE_FUNCTION(ScriptCanvas);
GraphCanvas::ExtenderSlotConfiguration graphCanvasConfiguration;

@ -8,7 +8,7 @@
if(LY_PIX_ENABLED)
file(TO_CMAKE_PATH "${LY_PIX_PATH}" PIX_PATH)
message(STATUS "PIX PATH ${PIX_PATH}")
message(STATUS "PIX found: ${PIX_PATH}")
ly_add_external_target(
NAME pix

@ -11,4 +11,4 @@ if(LY_MONOLITHIC_GAME)
else()
set(PIX_LIBS ${BASE_PATH}/bin/x64/WinPixEventRuntime.lib)
set(PIX_RUNTIME_DEPENDENCIES ${BASE_PATH}/bin/x64/WinPixEventRuntime.dll)
endif()
endif()

Loading…
Cancel
Save