Add preliminary budget tracking system and remove driller integration
Signed-off-by: Jeremy Ong <jcong@amazon.com>
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
|
||||
// Component includes
|
||||
#include <AzCore/Asset/AssetManagerComponent.h>
|
||||
#include <AzCore/Debug/BudgetsComponent.h>
|
||||
#include <AzCore/IO/Streamer/StreamerComponent.h>
|
||||
#include <AzCore/Jobs/JobManagerComponent.h>
|
||||
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
|
||||
@@ -36,7 +35,6 @@ namespace AZ
|
||||
JsonSystemComponent::CreateDescriptor(),
|
||||
AssetManagerComponent::CreateDescriptor(),
|
||||
UserSettingsComponent::CreateDescriptor(),
|
||||
Debug::BudgetsComponent::CreateDescriptor(),
|
||||
SliceComponent::CreateDescriptor(),
|
||||
SliceSystemComponent::CreateDescriptor(),
|
||||
SliceMetadataInfoComponent::CreateDescriptor(),
|
||||
@@ -54,7 +52,6 @@ namespace AZ
|
||||
{
|
||||
return AZ::ComponentTypeList
|
||||
{
|
||||
azrtti_typeid<Debug::BudgetsComponent>(),
|
||||
azrtti_typeid<TimeSystemComponent>(),
|
||||
azrtti_typeid<LoggerSystemComponent>(),
|
||||
azrtti_typeid<EventSchedulerSystemComponent>(),
|
||||
|
||||
@@ -593,6 +593,8 @@ namespace AZ
|
||||
CreateOSAllocator();
|
||||
CreateSystemAllocator();
|
||||
|
||||
m_budgetTracker.Init();
|
||||
|
||||
// This can be moved to the ComponentApplication constructor if need be
|
||||
// This is reading the *.setreg files using SystemFile and merging the settings
|
||||
// to the settings registry.
|
||||
@@ -624,8 +626,6 @@ namespace AZ
|
||||
m_eventLogger->Start(outputPath.Native(), baseFileName);
|
||||
}
|
||||
|
||||
CreateDrillers();
|
||||
|
||||
Sfmt::Create();
|
||||
|
||||
CreateReflectionManager();
|
||||
@@ -745,12 +745,6 @@ namespace AZ
|
||||
ComponentApplicationBus::Handler::BusDisconnect();
|
||||
TickRequestBus::Handler::BusDisconnect();
|
||||
|
||||
if (m_drillerManager)
|
||||
{
|
||||
Debug::DrillerManager::Destroy(m_drillerManager);
|
||||
m_drillerManager = nullptr;
|
||||
}
|
||||
|
||||
m_eventLogger->Stop();
|
||||
|
||||
// Clear the descriptor to deallocate all strings (owned by ModuleDescriptor)
|
||||
@@ -898,31 +892,6 @@ namespace AZ
|
||||
allocatorManager.FinalizeConfiguration();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// CreateDrillers
|
||||
// [2/20/2013]
|
||||
//=========================================================================
|
||||
void ComponentApplication::CreateDrillers()
|
||||
{
|
||||
// Create driller manager and register drillers if requested
|
||||
if (m_descriptor.m_enableDrilling)
|
||||
{
|
||||
m_drillerManager = Debug::DrillerManager::Create();
|
||||
// Memory driller is responsible for tracking allocations.
|
||||
// Tracking type and overhead is determined by app configuration.
|
||||
|
||||
// Only one MemoryDriller is supported at a time
|
||||
// Only create the memory driller if there is no handlers connected to the MemoryDrillerBus
|
||||
if (!Debug::MemoryDrillerBus::HasHandlers())
|
||||
{
|
||||
m_drillerManager->Register(aznew Debug::MemoryDriller);
|
||||
}
|
||||
// Trace messages driller will consume resources only when started.
|
||||
m_drillerManager->Register(aznew Debug::TraceMessagesDriller);
|
||||
m_drillerManager->Register(aznew Debug::EventTraceDriller);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentApplication::MergeSettingsToRegistry(SettingsRegistryInterface& registry)
|
||||
{
|
||||
SettingsRegistryInterface::Specializations specializations;
|
||||
@@ -1413,10 +1382,6 @@ namespace AZ
|
||||
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
|
||||
}
|
||||
}
|
||||
if (m_drillerManager)
|
||||
{
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Debug/BudgetTracker.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Module/DynamicModuleHandle.h>
|
||||
@@ -225,11 +226,6 @@ namespace AZ
|
||||
/// Returns the path to the folder the executable is in.
|
||||
const char* GetExecutableFolder() const override { return m_exeDirectory.c_str(); }
|
||||
|
||||
|
||||
/// Returns pointer to the driller manager if it's enabled, otherwise NULL.
|
||||
Debug::DrillerManager* GetDrillerManager() override { return m_drillerManager; }
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// TickRequestBus
|
||||
float GetTickDeltaTime() override;
|
||||
@@ -324,9 +320,6 @@ namespace AZ
|
||||
/// Create the system allocator using the data in the m_descriptor
|
||||
void CreateSystemAllocator();
|
||||
|
||||
/// Create the drillers
|
||||
void CreateDrillers();
|
||||
|
||||
virtual void MergeSettingsToRegistry(SettingsRegistryInterface& registry);
|
||||
|
||||
//! Sets the specializations that will be used when loading the Settings Registry. Extend this in derived
|
||||
@@ -409,7 +402,7 @@ namespace AZ
|
||||
char m_commandLineBuffer[AZ_MAX_PATH_LEN];
|
||||
char* m_commandLineBufferAddress{ m_commandLineBuffer };
|
||||
|
||||
Debug::DrillerManager* m_drillerManager{ nullptr };
|
||||
AZ::Debug::BudgetTracker m_budgetTracker;
|
||||
|
||||
StartupParameters m_startupParameters;
|
||||
|
||||
|
||||
@@ -187,11 +187,6 @@ namespace AZ
|
||||
//! @return a pointer to the name of the path that contains the application's executable.
|
||||
virtual const char* GetExecutableFolder() const = 0;
|
||||
|
||||
//! Returns a pointer to the driller manager, if driller is enabled.
|
||||
//! The driller manager manages all active driller sessions and driller factories.
|
||||
//! @return A pointer to the driller manager. If driller is not enabled, this function returns null.
|
||||
virtual Debug::DrillerManager* GetDrillerManager() = 0;
|
||||
|
||||
//! ResolveModulePath is called whenever LoadDynamicModule wants to resolve a module in order to actually load it.
|
||||
//! You can override this if you need to load modules from a different path or hijack module loading in some other way.
|
||||
//! If you do, ensure that you use platform-specific conventions to do so, as this is called by multiple platforms.
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(AzCore);
|
||||
AZ_DEFINE_BUDGET(Editor);
|
||||
@@ -21,25 +22,46 @@ AZ_DEFINE_BUDGET(Animation);
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
// Global container for all registered budgets
|
||||
class BudgetRegistry
|
||||
struct BudgetImpl
|
||||
{
|
||||
public:
|
||||
static BudgetRegistry& Instance()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
AZ_CLASS_ALLOCATOR(BudgetImpl, AZ::SystemAllocator, 0);
|
||||
// TODO: Budget implementation for tracking budget wall time per-core, memory, etc.
|
||||
};
|
||||
|
||||
void Budget::ResetAll()
|
||||
{
|
||||
}
|
||||
|
||||
Budget::Budget(const char* name)
|
||||
: m_name{ name }
|
||||
, m_crc{ Crc32(name) }
|
||||
{
|
||||
// TODO: Register budget with singleton budget registry
|
||||
m_impl = aznew BudgetImpl;
|
||||
}
|
||||
|
||||
Budget::~Budget()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:Budgets Methods below are stubbed pending future work to both update budget data and visualize it
|
||||
|
||||
void Budget::PerFrameReset()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::BeginProfileRegion()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::EndProfileRegion()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::TrackAllocation(uint64_t)
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::UntrackAllocation(uint64_t)
|
||||
{
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
#include <AzCore/Debug/BudgetTracker.h>
|
||||
|
||||
#pragma warning(push)
|
||||
// This warning must be disabled because Budget::Get<T> may not have an implementation if this file is transitively included
|
||||
@@ -24,9 +23,6 @@ namespace AZ::Debug
|
||||
class Budget final
|
||||
{
|
||||
public:
|
||||
// Invoked once at the start of the frame to reset per-frame counters
|
||||
static void ResetAll();
|
||||
|
||||
// If you encounter a linker error complaining that this function is not defined, you have likely forgotten to either
|
||||
// define or declare the budget used in a profile or memory marker. See AZ_DEFINE_BUDGET and AZ_DECLARE_BUDGET below
|
||||
// for usage.
|
||||
@@ -34,6 +30,13 @@ namespace AZ::Debug
|
||||
static Budget* Get();
|
||||
|
||||
explicit Budget(const char* name);
|
||||
~Budget();
|
||||
|
||||
void PerFrameReset();
|
||||
void BeginProfileRegion();
|
||||
void EndProfileRegion();
|
||||
void TrackAllocation(uint64_t bytes);
|
||||
void UntrackAllocation(uint64_t bytes);
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
@@ -48,11 +51,14 @@ namespace AZ::Debug
|
||||
private:
|
||||
const char* m_name;
|
||||
uint32_t m_crc;
|
||||
struct BudgetImpl* m_impl = nullptr;
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
#pragma warning(pop)
|
||||
|
||||
#define AZ_BUDGET_NAME(name) AzBudget##name
|
||||
// Budgets are registered and retrieved using the proxy type specialization of Budget::Get<T>. The type itself has no declaration/definition
|
||||
// other than this forward type pointer declaration
|
||||
#define AZ_BUDGET_PROXY_TYPE(name) class AzBudget##name*
|
||||
|
||||
// Usage example:
|
||||
// In a single C++ source file:
|
||||
@@ -62,45 +68,26 @@ namespace AZ::Debug
|
||||
// AZ_DECLARE_BUDGET(AzCore);
|
||||
//
|
||||
// The budget is usable in the same file it was defined without needing an additional declaration
|
||||
|
||||
// Implementation notes:
|
||||
// Every budget definition is declared in static storage along with the environment variable and mutex. This imposes a slight
|
||||
// memory overhead in the data segment only in instances where the same static module defining a budget is linked against multiple
|
||||
// DLLs, however, this simplifies the implementation and works regardless of whether the budget is defined in a static or dynamic
|
||||
// library. When loading the budget, a relaxed load is sufficient because Environment::CreateVariable internally locks and returns
|
||||
// the element found if the environment variable was already created (skipping construction in the process). Thus, the budget pointer
|
||||
// will reference the statically stored budget for the first thread that grabs the lock.
|
||||
#define AZ_DEFINE_BUDGET(name) \
|
||||
template<> \
|
||||
::AZ::Debug::Budget* ::AZ::Debug::Budget::Get<class AZ_BUDGET_NAME(name)*>() \
|
||||
::AZ::Debug::Budget* ::AZ::Debug::Budget::Get<AZ_BUDGET_PROXY_TYPE(name)>() \
|
||||
{ \
|
||||
static ::AZStd::mutex s_azBudgetMutex##name; \
|
||||
static ::AZ::EnvironmentVariable<::AZ::Debug::Budget*> s_azBudgetEnv##name; \
|
||||
static ::AZ::Debug::Budget s_azBudget##name{ #name }; \
|
||||
static ::AZStd::atomic<::AZ::Debug::Budget*> budget; \
|
||||
::AZ::Debug::Budget* out = budget.load(AZStd::memory_order_relaxed); \
|
||||
::AZ::Debug::Budget* out = budget.load(AZStd::memory_order_acquire); \
|
||||
if (out) \
|
||||
{ \
|
||||
return out; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
{ \
|
||||
AZStd::scoped_lock lock{ s_azBudgetMutex##name }; \
|
||||
if (!s_azBudgetEnv##name) \
|
||||
{ \
|
||||
s_azBudgetEnv##name = ::AZ::Environment::CreateVariable<::AZ::Debug::Budget*>("budgetEnv" #name, &s_azBudget##name); \
|
||||
} \
|
||||
} \
|
||||
out = *s_azBudgetEnv##name; \
|
||||
budget = out; \
|
||||
return out; \
|
||||
budget.store(&::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(#name), AZStd::memory_order_release); \
|
||||
return budget; \
|
||||
} \
|
||||
}
|
||||
|
||||
// If using a budget defined in a different C++ source file, add AZ_DECLARE_BUDGET(yourBudget); somewhere in your source file at namespace
|
||||
// scope Alternatively, AZ_DECLARE_BUDGET can be used in a header to declare the budget for use across any users of the header
|
||||
#define AZ_DECLARE_BUDGET(name) extern template ::AZ::Debug::Budget* ::AZ::Debug::Budget::Get<class AZ_BUDGET_NAME(name)*>()
|
||||
#define AZ_DECLARE_BUDGET(name) extern template ::AZ::Debug::Budget* ::AZ::Debug::Budget::Get<AZ_BUDGET_PROXY_TYPE(name)>()
|
||||
|
||||
// Declare budgets that are core engine budgets, or may be shared/needed across multiple external gems
|
||||
// You should NOT need to declare user-space or budgets with isolated usage here. Prefer declaring them local to the module(s) that use
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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/Debug/BudgetTracker.h>
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
constexpr static const char* BudgetTrackerEnvName = "budgetTrackerEnv";
|
||||
|
||||
struct BudgetTrackerImpl
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(BudgetTrackerImpl, AZ::SystemAllocator, 0);
|
||||
|
||||
AZStd::unordered_map<const char*, Budget> m_budgets;
|
||||
};
|
||||
|
||||
Budget& BudgetTracker::GetBudgetFromEnvironment(const char* budgetName)
|
||||
{
|
||||
return (*Environment::FindVariable<BudgetTracker*>(BudgetTrackerEnvName))->GetBudget(budgetName);
|
||||
}
|
||||
|
||||
BudgetTracker::~BudgetTracker()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
}
|
||||
|
||||
void BudgetTracker::Init()
|
||||
{
|
||||
AZ_Assert(!m_impl, "BudgetTracker::Init called more than once");
|
||||
|
||||
m_impl = aznew BudgetTrackerImpl;
|
||||
m_envVar = Environment::CreateVariable<BudgetTracker*>(BudgetTrackerEnvName, this);
|
||||
}
|
||||
|
||||
Budget& BudgetTracker::GetBudget(const char* budgetName)
|
||||
{
|
||||
AZStd::scoped_lock lock{ m_mutex };
|
||||
|
||||
auto it = m_impl->m_budgets.find(budgetName);
|
||||
if (it == m_impl->m_budgets.end())
|
||||
{
|
||||
it = m_impl->m_budgets.emplace(budgetName, budgetName).first;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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/Module/Environment.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class Budget;
|
||||
|
||||
class BudgetTracker
|
||||
{
|
||||
public:
|
||||
static Budget& GetBudgetFromEnvironment(const char* budgetName);
|
||||
|
||||
~BudgetTracker();
|
||||
|
||||
void Init();
|
||||
|
||||
Budget& GetBudget(const char* budgetName);
|
||||
|
||||
private:
|
||||
AZStd::mutex m_mutex;
|
||||
AZ::EnvironmentVariable<BudgetTracker*> m_envVar;
|
||||
|
||||
// The BudgetTracker is likely included in proportionally high number of files throughout the
|
||||
// engine, so indirection is used here to avoid imposing excessive recompilation in periods
|
||||
// while the budget system is iterated on.
|
||||
struct BudgetTrackerImpl* m_impl = nullptr;
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,29 +0,0 @@
|
||||
#include <AzCore/Debug/BudgetsComponent.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
void BudgetsComponent::Reflect(AZ::ReflectContext*)
|
||||
{
|
||||
}
|
||||
|
||||
BudgetsComponent::BudgetsComponent()
|
||||
{
|
||||
}
|
||||
|
||||
BudgetsComponent::~BudgetsComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void BudgetsComponent::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void BudgetsComponent::Activate()
|
||||
{
|
||||
}
|
||||
|
||||
void BudgetsComponent::Deactivate()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,31 +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>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class BudgetsComponent : public Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AZ::Debug::BudgetsComponent, "{52063706-5B36-4B24-A781-B49AFDBB5BC5}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
BudgetsComponent();
|
||||
~BudgetsComponent() override;
|
||||
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
private:
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
@@ -8,13 +8,3 @@
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
uint32_t ProfileScope::GetSystemID(const char* system)
|
||||
{
|
||||
// TODO: stable ids for registered budgets
|
||||
return AZ::Crc32(system);
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
|
||||
@@ -29,15 +29,15 @@
|
||||
#define AZ_PROFILE_SCOPE(budget, ...) \
|
||||
::AZ::Debug::ProfileScope AZ_JOIN(azProfileScope, __LINE__) \
|
||||
{ \
|
||||
*::AZ::Debug::Budget::Get<class AZ_BUDGET_NAME(budget)*>(), __VA_ARGS__ \
|
||||
*::AZ::Debug::Budget::Get<AZ_BUDGET_PROXY_TYPE(budget)>(), __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(budget, ...) \
|
||||
::AZ::Debug::ProfileScope::BeginRegion(*::AZ::Debug::Budget::Get<class AZ_BUDGET_NAME(budget)*>(), __VA_ARGS__)
|
||||
#define AZ_PROFILE_END() ::AZ::Debug::ProfileScope::EndRegion()
|
||||
::AZ::Debug::ProfileScope::BeginRegion(*::AZ::Debug::Budget::Get<AZ_BUDGET_PROXY_TYPE(budget)>(), __VA_ARGS__)
|
||||
#define AZ_PROFILE_END(budget) ::AZ::Debug::ProfileScope::EndRegion(*::AZ::Debug::Budget::Get<AZ_BUDGET_PROXY_TYPE(budget)>())
|
||||
|
||||
#endif // AZ_PROFILER_MACRO_DISABLE
|
||||
|
||||
@@ -63,26 +63,25 @@ namespace AZ::Debug
|
||||
class ProfileScope
|
||||
{
|
||||
public:
|
||||
static uint32_t GetSystemID(const char* system);
|
||||
|
||||
template<typename... T>
|
||||
static void BeginRegion(
|
||||
[[maybe_unused]] const Budget& budget, [[maybe_unused]] const char* eventName, [[maybe_unused]] T const&... args)
|
||||
static void BeginRegion([[maybe_unused]] Budget& budget, [[maybe_unused]] const char* eventName, [[maybe_unused]] T const&... args)
|
||||
{
|
||||
#if !defined(_RELEASE)
|
||||
// TODO: Verification that the supplied system name corresponds to a known budget
|
||||
#if defined(USE_PIX)
|
||||
PIXBeginEvent(PIX_COLOR_INDEX(budget.Crc() & 0xff), eventName, args...);
|
||||
#endif
|
||||
budget.BeginProfileRegion();
|
||||
// TODO: injecting instrumentation for other profilers
|
||||
// NOTE: external profiler registration won't occur inline in a header necessarily in this manner, but the exact mechanism
|
||||
// will be introduced in a future PR
|
||||
#endif
|
||||
}
|
||||
|
||||
static void EndRegion()
|
||||
static void EndRegion([[maybe_unused]] Budget& budget)
|
||||
{
|
||||
#if !defined(_RELEASE)
|
||||
budget.EndProfileRegion();
|
||||
#if defined(USE_PIX)
|
||||
PIXEndEvent();
|
||||
#endif
|
||||
@@ -90,15 +89,19 @@ namespace AZ::Debug
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
ProfileScope(const Budget& budget, char const* eventName, T const&... args)
|
||||
ProfileScope(Budget& budget, char const* eventName, T const&... args)
|
||||
: m_budget{ budget }
|
||||
{
|
||||
BeginRegion(budget, eventName, args...);
|
||||
}
|
||||
|
||||
~ProfileScope()
|
||||
{
|
||||
EndRegion();
|
||||
EndRegion(m_budget);
|
||||
}
|
||||
|
||||
private:
|
||||
Budget& m_budget;
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace UnitTest
|
||||
MOCK_CONST_METHOD0(GetAppRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetEngineRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
|
||||
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
|
||||
MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
|
||||
};
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -95,8 +95,8 @@ set(FILES
|
||||
Debug/AssetTrackingTypes.h
|
||||
Debug/Budget.h
|
||||
Debug/Budget.cpp
|
||||
Debug/BudgetsComponent.h
|
||||
Debug/BudgetsComponent.cpp
|
||||
Debug/BudgetTracker.h
|
||||
Debug/BudgetTracker.cpp
|
||||
Debug/LocalFileEventLogger.h
|
||||
Debug/LocalFileEventLogger.cpp
|
||||
Debug/IEventLogger.h
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace UnitTest
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
////
|
||||
|
||||
@@ -1,698 +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 <time.h>
|
||||
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
#include <AzCore/Driller/DrillerRootHandler.h>
|
||||
#include <AzCore/Driller/DefaultStringPool.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
#include <AzCore/IO/Streamer/StreamerComponent.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
//#define AZ_CORE_DRILLER_COMPARE_TEST
|
||||
#if defined(AZ_CORE_DRILLER_COMPARE_TEST)
|
||||
# include <AzCore/IO/GenericStreams.h>
|
||||
# include <AzCore/Serialization/ObjectStream.h>
|
||||
# include <AzCore/Serialization/SerializeContext.h>
|
||||
#endif
|
||||
|
||||
#include <AZTestShared/Utils/Utils.h>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace AZ::Debug;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
/**
|
||||
* MyDriller event bus...
|
||||
*/
|
||||
class MyDrillerInterface
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~MyDrillerInterface() {}
|
||||
// define one event X
|
||||
virtual void OnEventX(int data) = 0;
|
||||
// define a string event
|
||||
virtual void OnStringEvent() = 0;
|
||||
};
|
||||
|
||||
class MyDrillerCommandInterface
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~MyDrillerCommandInterface() {}
|
||||
|
||||
virtual class MyDrilledObject* RequestDrilledObject() = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<MyDrillerInterface> MyDrillerBus;
|
||||
typedef AZ::EBus<MyDrillerCommandInterface> MyDrillerCommandBus;
|
||||
|
||||
class MyDrilledObject
|
||||
: public MyDrillerCommandBus::Handler
|
||||
{
|
||||
int i;
|
||||
public:
|
||||
MyDrilledObject()
|
||||
: i(0)
|
||||
{
|
||||
BusConnect();
|
||||
}
|
||||
|
||||
~MyDrilledObject() override
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MyDrillerCommandBus
|
||||
MyDrilledObject* RequestDrilledObject() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void OnEventX()
|
||||
{
|
||||
EBUS_EVENT(MyDrillerBus, OnEventX, i);
|
||||
++i;
|
||||
}
|
||||
|
||||
void OnStringEvent()
|
||||
{
|
||||
EBUS_DBG_EVENT(MyDrillerBus, OnStringEvent);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* My driller implements the driller interface and an handles the MyDrillerBus events...
|
||||
*/
|
||||
class MyDriller
|
||||
: public Driller
|
||||
, public MyDrillerBus::Handler
|
||||
{
|
||||
bool m_isDetailedCapture;
|
||||
class MyDrilledObject* drilledObject;
|
||||
typedef vector<Param>::type ParamArrayType;
|
||||
ParamArrayType m_params;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MyDriller, OSAllocator, 0);
|
||||
|
||||
const char* GroupName() const override { return "TestDrillers"; }
|
||||
const char* GetName() const override { return "MyTestDriller"; }
|
||||
const char* GetDescription() const override { return "MyTestDriller description...."; }
|
||||
int GetNumParams() const override { return static_cast<int>(m_params.size()); }
|
||||
const Param* GetParam(int index) const override { return &m_params[index]; }
|
||||
|
||||
MyDriller()
|
||||
: m_isDetailedCapture(false)
|
||||
, drilledObject(NULL)
|
||||
{
|
||||
Param isDetailed;
|
||||
isDetailed.desc = "IsDetailedDrill";
|
||||
isDetailed.name = AZ_CRC("IsDetailedDrill", 0x2155cef2);
|
||||
isDetailed.type = Param::PT_BOOL;
|
||||
isDetailed.value = 0;
|
||||
m_params.push_back(isDetailed);
|
||||
}
|
||||
|
||||
void Start(const Param* params = NULL, int numParams = 0) override
|
||||
{
|
||||
m_isDetailedCapture = m_params[0].value != 0;
|
||||
if (params)
|
||||
{
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
if (params[i].name == m_params[0].name)
|
||||
{
|
||||
m_isDetailedCapture = params[i].value != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EBUS_EVENT_RESULT(drilledObject, MyDrillerCommandBus, RequestDrilledObject);
|
||||
AZ_TEST_ASSERT(drilledObject != NULL); /// Make sure we have our object by the time we started the driller
|
||||
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("OnStart", 0x8b372fca), m_isDetailedCapture);
|
||||
// write drilled object initial state
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
|
||||
BusConnect();
|
||||
}
|
||||
void Stop() override
|
||||
{
|
||||
drilledObject = NULL;
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("OnStop", 0xf6701caa), m_isDetailedCapture);
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
BusDisconnect();
|
||||
}
|
||||
|
||||
void OnEventX(int data) override
|
||||
{
|
||||
void* ptr = AZ_INVALID_POINTER;
|
||||
float f = 3.2f;
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("EventX", 0xc4558ec2), data);
|
||||
m_output->Write(AZ_CRC("Pointer", 0x320468a8), ptr);
|
||||
m_output->Write(AZ_CRC("Float", 0xc9a55e95), f);
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
}
|
||||
|
||||
void OnStringEvent() override
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->BeginTag(AZ_CRC("StringEvent", 0xd1e005df));
|
||||
m_output->Write(AZ_CRC("StringOne", 0x56efb231), "This is copied string");
|
||||
m_output->Write(AZ_CRC("StringTwo", 0x3d49bea6), "This is referenced string", false); // don't copy the string if we use string pool, this will be faster as we don't delete the string
|
||||
m_output->EndTag(AZ_CRC("StringEvent", 0xd1e005df));
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class FileStreamDrillerTest
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
DrillerManager* m_drillerManager = nullptr;
|
||||
MyDriller* m_driller = nullptr;
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_drillerManager = DrillerManager::Create();
|
||||
m_driller = aznew MyDriller;
|
||||
// Register driller descriptor
|
||||
m_drillerManager->Register(m_driller);
|
||||
// check that our driller descriptor is registered
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// remove our driller descriptor
|
||||
m_drillerManager->Unregister(m_driller);
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 0);
|
||||
DrillerManager::Destroy(m_drillerManager);
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* My Driller data handler.
|
||||
*/
|
||||
class MyDrillerHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
static const bool s_isWarnOnMissingDrillers = true;
|
||||
int m_lastData;
|
||||
|
||||
MyDrillerHandler()
|
||||
: m_lastData(-1) {}
|
||||
|
||||
// From the template query
|
||||
DrillerHandlerParser* FindDrillerHandler(u32 drillerId)
|
||||
{
|
||||
if (drillerId == AZ_CRC("MyDriller", 0xc3b7dceb))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* OnEnterTag(u32 tagName) override
|
||||
{
|
||||
(void)tagName;
|
||||
return NULL;
|
||||
}
|
||||
void OnData(const DrillerSAXParser::Data& dataNode) override
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("OnStart", 0x8b372fca) || dataNode.m_name == AZ_CRC("OnStop", 0xf6701caa))
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataNode.Read(isDetailedCapture);
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("EventX", 0xc4558ec2))
|
||||
{
|
||||
int data;
|
||||
dataNode.Read(data);
|
||||
AZ_TEST_ASSERT(data > m_lastData);
|
||||
m_lastData = data;
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Pointer", 0x320468a8))
|
||||
{
|
||||
AZ::u64 pointer = 0; //< read pointers in u64 to cover all platforms
|
||||
dataNode.Read(pointer);
|
||||
AZ_TEST_ASSERT(pointer == 0x0badf00dul);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Float", 0xc9a55e95))
|
||||
{
|
||||
float f;
|
||||
dataNode.Read(f);
|
||||
AZ_TEST_ASSERT(f == 3.2f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void run()
|
||||
{
|
||||
// get our driller descriptor
|
||||
Driller* driller = m_drillerManager->GetDriller(0);
|
||||
AZ_TEST_ASSERT(driller != NULL);
|
||||
AZ_TEST_ASSERT(strcmp(driller->GetName(), "MyTestDriller") == 0);
|
||||
AZ_TEST_ASSERT(driller->GetNumParams() == 1);
|
||||
|
||||
// read the default params and make a copy...
|
||||
Driller::Param param = *driller->GetParam(0);
|
||||
AZ_TEST_ASSERT(strcmp(param.desc, "IsDetailedDrill") == 0);
|
||||
AZ_TEST_ASSERT(param.name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(param.type == Driller::Param::PT_BOOL);
|
||||
// tweak the default params by enabling detailed drilling
|
||||
param.value = 1;
|
||||
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType dillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = driller->GetId(); // set driller id
|
||||
di.params.push_back(param); // set driller custom params
|
||||
dillersToDrill.push_back(di);
|
||||
|
||||
// open a driller output file stream
|
||||
// open a driller output file stream
|
||||
AZStd::string testFileName = GetTestFolderPath() + "drilltest.dat";
|
||||
DrillerOutputFileStream drillerOutputStream;
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object
|
||||
MyDrilledObject myDrilledObject;
|
||||
clock_t st = clock();
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
DrillerSession* drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
// trigger event X that we want to drill...
|
||||
myDrilledObject.OnEventX();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
AZ_Printf("Driller", "Compression time %.09f seconds\n", (double)(clock() - st) / CLOCKS_PER_SEC);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// try to load the drill data
|
||||
DrillerInputFileStream drillerInputStream;
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
DrillerDOMParser dp;
|
||||
AZ_TEST_ASSERT(dp.CanParse() == true);
|
||||
dp.ProcessStream(drillerInputStream);
|
||||
AZ_TEST_ASSERT(dp.CanParse() == true);
|
||||
drillerInputStream.Close();
|
||||
|
||||
u32 startDataId = AZ_CRC("StartData", 0xecf3f53f);
|
||||
u32 frameId = AZ_CRC("Frame", 0xb5f83ccd);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// read all data
|
||||
const DrillerDOMParser::Node* root = dp.GetRootNode();
|
||||
int lastFrame = -1;
|
||||
int lastData = -1;
|
||||
for (DrillerDOMParser::Node::NodeListType::const_iterator iter = root->m_tags.begin(); iter != root->m_tags.end(); ++iter)
|
||||
{
|
||||
const DrillerDOMParser::Node* node = &*iter;
|
||||
u32 name = node->m_name;
|
||||
AZ_TEST_ASSERT(name == startDataId || name == frameId);
|
||||
if (name == startDataId)
|
||||
{
|
||||
unsigned int currentPlatform;
|
||||
node->GetDataRequired(AZ_CRC("Platform", 0x3952d0cb))->Read(currentPlatform);
|
||||
AZ_TEST_ASSERT(currentPlatform == static_cast<int>(AZ::g_currentPlatform));
|
||||
const DrillerDOMParser::Node* drillerNode = node->GetTag(AZ_CRC("Driller", 0xa6e1fb73));
|
||||
AZ_TEST_ASSERT(drillerNode != NULL);
|
||||
AZ::u32 drillerName;
|
||||
drillerNode->GetDataRequired(AZ_CRC("Name", 0x5e237e06))->Read(drillerName);
|
||||
AZ_TEST_ASSERT(drillerName == m_driller->GetId());
|
||||
const DrillerDOMParser::Node* paramNode = drillerNode->GetTag(AZ_CRC("Param", 0xa4fa7c89));
|
||||
AZ_TEST_ASSERT(paramNode != NULL);
|
||||
u32 paramName;
|
||||
char paramDesc[128];
|
||||
int paramType;
|
||||
int paramValue;
|
||||
paramNode->GetDataRequired(AZ_CRC("Name", 0x5e237e06))->Read(paramName);
|
||||
AZ_TEST_ASSERT(paramName == param.name);
|
||||
paramNode->GetDataRequired(AZ_CRC("Description", 0x6de44026))->Read(paramDesc, AZ_ARRAY_SIZE(paramDesc));
|
||||
AZ_TEST_ASSERT(strcmp(paramDesc, param.desc) == 0);
|
||||
paramNode->GetDataRequired(AZ_CRC("Type", 0x8cde5729))->Read(paramType);
|
||||
AZ_TEST_ASSERT(paramType == param.type);
|
||||
paramNode->GetDataRequired(AZ_CRC("Value", 0x1d775834))->Read(paramValue);
|
||||
AZ_TEST_ASSERT(paramValue == param.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
int curFrame;
|
||||
node->GetDataRequired(AZ_CRC("FrameNum", 0x85a1a919))->Read(curFrame);
|
||||
AZ_TEST_ASSERT(curFrame > lastFrame); // check order
|
||||
lastFrame = curFrame;
|
||||
const DrillerDOMParser::Node* myDrillerNode = node->GetTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
AZ_TEST_ASSERT(myDrillerNode != NULL);
|
||||
const DrillerDOMParser::Data* dataEntry;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("EventX", 0xc4558ec2));
|
||||
if (dataEntry)
|
||||
{
|
||||
int data;
|
||||
dataEntry->Read(data);
|
||||
AZ_TEST_ASSERT(data > lastData);
|
||||
lastData = data;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("Pointer", 0x320468a8));
|
||||
AZ_TEST_ASSERT(dataEntry);
|
||||
unsigned int ptr;
|
||||
dataEntry->Read(ptr);
|
||||
AZ_TEST_ASSERT(static_cast<size_t>(ptr) == reinterpret_cast<size_t>(AZ_INVALID_POINTER));
|
||||
float f;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("Float", 0xc9a55e95));
|
||||
AZ_TEST_ASSERT(dataEntry);
|
||||
dataEntry->Read(f);
|
||||
AZ_TEST_ASSERT(f == 3.2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("OnStart", 0x8b372fca));
|
||||
if (dataEntry)
|
||||
{
|
||||
dataEntry->Read(isDetailedCapture);
|
||||
}
|
||||
else
|
||||
{
|
||||
myDrillerNode->GetDataRequired(AZ_CRC("OnStop", 0xf6701caa))->Read(isDetailedCapture);
|
||||
}
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read that with Tag Handlers
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
|
||||
DrillerRootHandler<MyDrillerHandler> rootHandler;
|
||||
DrillerSAXParserHandler dhp(&rootHandler);
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
// Verify that Default templates forked fine...
|
||||
AZ_TEST_ASSERT(rootHandler.m_drillerSessionInfo.m_platform == static_cast<uint32_t>(AZ::g_currentPlatform));
|
||||
AZ_TEST_ASSERT(rootHandler.m_drillerSessionInfo.m_drillers.size() == 1);
|
||||
{
|
||||
const DrillerManager::DrillerInfo& dinfo = rootHandler.m_drillerSessionInfo.m_drillers.front();
|
||||
AZ_TEST_ASSERT(dinfo.id == AZ_CRC("MyTestDriller", 0x5cc4edf5));
|
||||
AZ_TEST_ASSERT(dinfo.params.size() == 1);
|
||||
AZ_TEST_ASSERT(strcmp(param.desc, "IsDetailedDrill") == 0);
|
||||
AZ_TEST_ASSERT(param.name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(param.type == Driller::Param::PT_BOOL);
|
||||
// tweak the default params by enabling detailed drilling
|
||||
param.value = 1;
|
||||
AZ_TEST_ASSERT(dinfo.params[0].name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(dinfo.params[0].desc == NULL); // ignored for now
|
||||
AZ_TEST_ASSERT(dinfo.params[0].type == Driller::Param::PT_BOOL);
|
||||
AZ_TEST_ASSERT(dinfo.params[0].value == 1);
|
||||
}
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FileStreamDrillerTest, Test)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class StringPoolDrillerTest
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
DrillerManager* m_drillerManager = nullptr;
|
||||
MyDriller* m_driller = nullptr;
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_drillerManager = DrillerManager::Create();
|
||||
m_driller = aznew MyDriller;
|
||||
// Register driller descriptor
|
||||
m_drillerManager->Register(m_driller);
|
||||
// check that our driller descriptor is registered
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// remove our driller descriptor
|
||||
m_drillerManager->Unregister(m_driller);
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 0);
|
||||
DrillerManager::Destroy(m_drillerManager);
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* My Driller data handler.
|
||||
*/
|
||||
class MyDrillerHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
static const bool s_isWarnOnMissingDrillers = true;
|
||||
|
||||
MyDrillerHandler() {}
|
||||
|
||||
// From the template query
|
||||
DrillerHandlerParser* FindDrillerHandler(u32 drillerId)
|
||||
{
|
||||
if (drillerId == AZ_CRC("MyDriller", 0xc3b7dceb))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* OnEnterTag(u32 tagName) override
|
||||
{
|
||||
if (tagName == AZ_CRC("StringEvent", 0xd1e005df))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void OnData(const DrillerSAXParser::Data& dataNode) override
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("OnStart", 0x8b372fca) || dataNode.m_name == AZ_CRC("OnStop", 0xf6701caa))
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataNode.Read(isDetailedCapture);
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("StringOne", 0x56efb231))
|
||||
{
|
||||
// read string as a copy
|
||||
char stringCopy[256];
|
||||
dataNode.Read(stringCopy, AZ_ARRAY_SIZE(stringCopy));
|
||||
AZ_TEST_ASSERT(strcmp(stringCopy, "This is copied string") == 0);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("StringTwo", 0x3d49bea6))
|
||||
{
|
||||
// read string as reference if possible, otherwise read it as a copy
|
||||
const char* stringRef = dataNode.ReadPooledString();
|
||||
AZ_TEST_ASSERT(strcmp(stringRef, "This is referenced string") == 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
// get our driller descriptor
|
||||
Driller* driller = m_drillerManager->GetDriller(0);
|
||||
Driller::Param param = *driller->GetParam(0);
|
||||
param.value = 1;
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType dillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = driller->GetId(); // set driller id
|
||||
di.params.push_back(param); // set driller custom params
|
||||
dillersToDrill.push_back(di);
|
||||
|
||||
MyDrilledObject myDrilledObject;
|
||||
|
||||
// open a driller output file stream
|
||||
AZStd::string testFileName = GetTestFolderPath() + "stringpooldrilltest.dat";
|
||||
DrillerOutputFileStream drillerOutputStream;
|
||||
DrillerInputFileStream drillerInputStream;
|
||||
DrillerDefaultStringPool stringPool;
|
||||
DrillerSession* drillerSession;
|
||||
DrillerRootHandler<MyDrillerHandler> rootHandler;
|
||||
DrillerSAXParserHandler dhp(&rootHandler);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object without string pools
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
myDrilledObject.OnStringEvent();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read all data that was written without string pool, in a stream that uses one.
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
drillerInputStream.SetStringPool(&stringPool);
|
||||
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object without string pools
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
stringPool.Reset();
|
||||
drillerOutputStream.SetStringPool(&stringPool); // set the string pool on save
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
myDrilledObject.OnStringEvent();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read all data that was written without string pool, in a stream that uses one.
|
||||
stringPool.Reset();
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
drillerInputStream.SetStringPool(&stringPool);
|
||||
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(StringPoolDrillerTest, Test)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class DrillFileStreamCheck
|
||||
{
|
||||
public:
|
||||
void run()
|
||||
{
|
||||
// open and read drilled file
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Driller application test
|
||||
*/
|
||||
TEST(DrillerApplication, Test)
|
||||
{
|
||||
ComponentApplication app;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Create application environment code driven
|
||||
ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
|
||||
appDesc.m_enableDrilling = true;
|
||||
Entity* systemEntity = app.Create(appDesc);
|
||||
|
||||
systemEntity->CreateComponent<MemoryComponent>();
|
||||
systemEntity->CreateComponent<StreamerComponent>(); // note that this component is what registers the streamer driller
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->Activate();
|
||||
|
||||
{
|
||||
// open a driller output file stream
|
||||
char testFileName[AZ_MAX_PATH_LEN];
|
||||
MakePathFromTestFolder(testFileName, AZ_MAX_PATH_LEN, "drillapptest.dat");
|
||||
DrillerOutputFileStream fs;
|
||||
fs.Open(testFileName, IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType drillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = AZ_CRC("TraceMessagesDriller", 0xa61d1b00);
|
||||
drillersToDrill.push_back(di);
|
||||
di.id = AZ_CRC("MemoryDriller", 0x1b31269d);
|
||||
drillersToDrill.push_back(di);
|
||||
|
||||
ASSERT_NE(nullptr, app.GetDrillerManager());
|
||||
DrillerSession* drillerSession = app.GetDrillerManager()->Start(fs, drillersToDrill);
|
||||
ASSERT_NE(nullptr, drillerSession);
|
||||
|
||||
const int numOfFrames = 10000;
|
||||
void* memory = NULL;
|
||||
for (int i = 0; i < numOfFrames; ++i)
|
||||
{
|
||||
memory = azmalloc(rand() % 2048 + 1);
|
||||
azfree(memory);
|
||||
app.Tick();
|
||||
}
|
||||
|
||||
app.GetDrillerManager()->Stop(drillerSession); // stop session manually
|
||||
fs.Close(); // close the file with driller info
|
||||
}
|
||||
|
||||
app.Destroy();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
}
|
||||
@@ -1242,7 +1242,6 @@ namespace UnitTest
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -29,7 +29,6 @@ set(FILES
|
||||
Console/ConsoleTests.cpp
|
||||
Debug.cpp
|
||||
DLL.cpp
|
||||
Driller.cpp
|
||||
EBus.cpp
|
||||
EntityIdTests.cpp
|
||||
EntityTests.cpp
|
||||
|
||||
Reference in New Issue
Block a user