Redcode/driller removal
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -19,7 +19,7 @@ using namespace ::testing;
|
||||
namespace UnitTest
|
||||
{
|
||||
class TestingClickableLabel
|
||||
: public testing::Test
|
||||
: public ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
ClickableLabel m_clickableLabel;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -22,7 +23,7 @@ namespace CryEditDocPythonBindingsUnitTests
|
||||
{
|
||||
|
||||
class CryEditDocPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +31,6 @@ namespace CryEditDocPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -24,7 +25,7 @@ namespace CryEditPythonBindingsUnitTests
|
||||
{
|
||||
|
||||
class CryEditPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -32,7 +33,6 @@ namespace CryEditPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -22,7 +23,7 @@ namespace DisplaySettingsPythonBindingsUnitTests
|
||||
{
|
||||
|
||||
class DisplaySettingsPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +31,6 @@ namespace DisplaySettingsPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
m_app.RegisterComponentDescriptor(AzToolsFramework::DisplaySettingsPythonFuncsHandler::CreateDescriptor());
|
||||
@@ -52,7 +52,7 @@ namespace DisplaySettingsPythonBindingsUnitTests
|
||||
}
|
||||
|
||||
class DisplaySettingsComponentFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -60,7 +60,6 @@ namespace DisplaySettingsPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
m_app.RegisterComponentDescriptor(AzToolsFramework::DisplaySettingsComponent::CreateDescriptor());
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -79,7 +80,7 @@ namespace EditorPythonBindingsUnitTests
|
||||
};
|
||||
|
||||
class EditorPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -87,7 +88,6 @@ namespace EditorPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
namespace EditorUtilsTest
|
||||
{
|
||||
@@ -39,7 +40,7 @@ namespace EditorUtilsTest
|
||||
|
||||
|
||||
class TestWarningAbsorber
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -22,7 +23,7 @@ namespace MainWindowPythonBindingsUnitTests
|
||||
{
|
||||
|
||||
class MainWindowPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +31,6 @@ namespace MainWindowPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -22,7 +23,7 @@ namespace ObjectManagerPythonBindingsUnitTests
|
||||
{
|
||||
|
||||
class ObjectManagerPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +31,6 @@ namespace ObjectManagerPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace TerrainFuncsUnitTests
|
||||
{
|
||||
|
||||
class TerrainHoleToolPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -31,7 +31,6 @@ namespace TerrainFuncsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace TerrainFuncsUnitTests
|
||||
{
|
||||
|
||||
class TerrainLayerPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -31,7 +31,6 @@ namespace TerrainFuncsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace TerrainModifyPythonBindingsUnitTests
|
||||
{
|
||||
|
||||
class TerrainModifyPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +30,6 @@ namespace TerrainModifyPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace TerrainFuncsUnitTests
|
||||
{
|
||||
|
||||
class TerrainPainterPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -31,7 +31,6 @@ namespace TerrainFuncsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace TerrainFuncsUnitTests
|
||||
{
|
||||
|
||||
class TerrainPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -31,7 +31,6 @@ namespace TerrainFuncsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace TerrainFuncsUnitTests
|
||||
{
|
||||
|
||||
class TerrainTexturePythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -31,7 +31,6 @@ namespace TerrainFuncsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -22,7 +23,7 @@ namespace TrackViewPythonBindingsUnitTests
|
||||
{
|
||||
|
||||
class TrackViewPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +31,6 @@ namespace TrackViewPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
@@ -82,7 +82,7 @@ namespace TrackViewPythonBindingsUnitTests
|
||||
}
|
||||
|
||||
class TrackViewComponentFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -90,7 +90,6 @@ namespace TrackViewPythonBindingsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
m_app.RegisterComponentDescriptor(AzToolsFramework::TrackViewComponent::CreateDescriptor());
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
@@ -22,7 +23,7 @@ namespace ViewPaneFuncsUnitTests
|
||||
{
|
||||
|
||||
class ViewPanePythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +31,6 @@ namespace ViewPaneFuncsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
@@ -22,7 +23,7 @@ namespace ViewportTitleDlgFuncsUnitTests
|
||||
{
|
||||
|
||||
class ViewportTitleDlgPythonBindingsFixture
|
||||
: public testing::Test
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
@@ -30,7 +31,6 @@ namespace ViewportTitleDlgFuncsUnitTests
|
||||
void SetUp() override
|
||||
{
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
m_app.Start(appDesc);
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace AZ
|
||||
using namespace AZ;
|
||||
|
||||
// Handle asserts
|
||||
class TraceDrillerHook
|
||||
class TestEnvironmentHook
|
||||
: public AZ::Test::ITestEnvironment
|
||||
, public UnitTest::TraceBusRedirector
|
||||
{
|
||||
@@ -57,5 +57,5 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
AZ_UNIT_TEST_HOOK(new TraceDrillerHook());
|
||||
AZ_UNIT_TEST_HOOK(new TestEnvironmentHook());
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzCore/std/typetraits/is_base_of.h>
|
||||
#include <AzCore/Debug/AssetTracking.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -581,7 +580,6 @@ namespace AZ
|
||||
template<typename Bus>
|
||||
using ConnectionPolicy = AssetConnectionPolicy<Bus>;
|
||||
|
||||
using EventProcessingPolicy = Debug::AssetTrackingEventProcessingPolicy<>;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~AssetEvents() {}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <AzCore/Asset/AssetManager_private.h>
|
||||
#include <AzCore/Asset/AssetDataStream.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Debug/AssetTracking.h>
|
||||
#include <AzCore/IO/IStreamer.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
@@ -164,8 +163,6 @@ namespace AZ::Data
|
||||
AZ_PROFILE_SCOPE(AzCore, "AZ::Data::LoadAssetJob::Process: %s",
|
||||
asset.GetHint().c_str());
|
||||
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(this);
|
||||
|
||||
if (m_owner->ValidateAndRegisterAssetLoading(asset))
|
||||
{
|
||||
LoadAndSignal(asset);
|
||||
@@ -200,7 +197,6 @@ namespace AZ::Data
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(cl_assetLoadDelay));
|
||||
}
|
||||
|
||||
AZ_ASSET_NAMED_SCOPE(asset.GetHint().c_str());
|
||||
bool loadedSuccessfully = false;
|
||||
|
||||
if (!cl_assetLoadError && m_requestState == AZ::IO::IStreamerTypes::RequestStatus::Completed)
|
||||
@@ -982,7 +978,6 @@ namespace AZ::Data
|
||||
}
|
||||
|
||||
AZ_PROFILE_SCOPE(AzCore, "GetAsset: %s", assetInfo.m_relativePath.c_str());
|
||||
AZ_ASSET_NAMED_SCOPE("GetAsset: %s", assetInfo.m_relativePath.c_str());
|
||||
|
||||
AZStd::shared_ptr<AssetDataStream> dataStream;
|
||||
AssetStreamInfo loadInfo;
|
||||
|
||||
@@ -48,10 +48,6 @@
|
||||
#include <AzCore/IO/Path/PathReflect.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Memory/MemoryDriller.h>
|
||||
#include <AzCore/Debug/TraceMessagesDriller.h>
|
||||
#include <AzCore/Debug/EventTraceDriller.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Script/ScriptSystemBus.h>
|
||||
|
||||
@@ -156,7 +152,6 @@ namespace AZ
|
||||
m_reservedDebug = 0;
|
||||
m_recordingMode = Debug::AllocationRecords::RECORD_STACK_IF_NO_FILE_LINE;
|
||||
m_stackRecordLevels = 5;
|
||||
m_enableDrilling = false;
|
||||
m_useOverrunDetection = false;
|
||||
m_useMalloc = false;
|
||||
}
|
||||
@@ -328,7 +323,6 @@ namespace AZ
|
||||
->Field("blockSize", &Descriptor::m_memoryBlocksByteSize)
|
||||
->Field("reservedOS", &Descriptor::m_reservedOS)
|
||||
->Field("reservedDebug", &Descriptor::m_reservedDebug)
|
||||
->Field("enableDrilling", &Descriptor::m_enableDrilling)
|
||||
->Field("useOverrunDetection", &Descriptor::m_useOverrunDetection)
|
||||
->Field("useMalloc", &Descriptor::m_useMalloc)
|
||||
->Field("allocatorRemappings", &Descriptor::m_allocatorRemappings)
|
||||
@@ -367,7 +361,6 @@ namespace AZ
|
||||
->Attribute(Edit::Attributes::Step, &Descriptor::m_pageSize)
|
||||
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_reservedOS, "OS reserved memory", "System memory reserved for OS (used only when 'Allocate all memory at startup' is true)")
|
||||
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_reservedDebug, "Memory reserved for debugger", "System memory reserved for Debug allocator, like memory tracking (used only when 'Allocate all memory at startup' is true)")
|
||||
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_enableDrilling, "Enable Driller", "Enable Drilling support for the application (ignored in Release builds)")
|
||||
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_useOverrunDetection, "Use Overrun Detection", "Use the overrun detection memory manager (only available on some platforms, ignored in Release builds)")
|
||||
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_useMalloc, "Use Malloc", "Use malloc for memory allocations (for memory debugging only, ignored in Release builds)")
|
||||
;
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace AZ
|
||||
}
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class DrillerManager;
|
||||
class LocalFileEventLogger;
|
||||
}
|
||||
|
||||
@@ -143,7 +142,6 @@ namespace AZ
|
||||
AZ::u64 m_reservedDebug; //!< Reserved memory for Debugging (allocation,etc.). Used only when m_grabAllMemory is set to true. (default: 0)
|
||||
Debug::AllocationRecords::Mode m_recordingMode; //!< When to record stack traces (default: AZ::Debug::AllocationRecords::RECORD_STACK_IF_NO_FILE_LINE)
|
||||
AZ::u64 m_stackRecordLevels; //!< If stack recording is enabled, how many stack levels to record. (default: 5)
|
||||
bool m_enableDrilling; //!< True to enabled drilling support for the application. RegisterDrillers will be called. Ignored in release. (default: true)
|
||||
bool m_useOverrunDetection; //!< True to use the overrun detection memory management scheme. Only available on some platforms; greatly increases memory consumption.
|
||||
bool m_useMalloc; //!< True to use malloc instead of the internal memory manager. Intended for debugging purposes only.
|
||||
|
||||
|
||||
@@ -37,11 +37,6 @@ namespace AZ
|
||||
class ComponentFactoryInterface;
|
||||
}
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
class DrillerManager;
|
||||
}
|
||||
|
||||
struct ApplicationTypeQuery
|
||||
{
|
||||
bool IsEditor() const;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#define AZCORE_COMPONENT_TICK_BUS_H
|
||||
|
||||
#include <AzCore/Component/ComponentBus.h>
|
||||
#include <AzCore/Debug/AssetTracking.h>
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/parallel/mutex.h> // For TickBus thread events.
|
||||
#include <AzCore/Script/ScriptTimePoint.h>
|
||||
@@ -112,10 +111,6 @@ namespace AZ
|
||||
AZ_FORCE_INLINE bool operator()(TickEvents* left, TickEvents* right) const { return left->GetTickOrder() < right->GetTickOrder(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable tick bus to work with the AssetTracking
|
||||
*/
|
||||
using EventProcessingPolicy = Debug::AssetTrackingEventProcessingPolicy<>;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
@@ -217,10 +212,6 @@ namespace AZ
|
||||
*/
|
||||
typedef AZStd::mutex EventQueueMutexType;
|
||||
|
||||
/**
|
||||
* Enable tick bus to work with the AssetTracking
|
||||
*/
|
||||
using EventProcessingPolicy = Debug::AssetTrackingEventProcessingPolicy<>;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,326 +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 "AssetTracking.h"
|
||||
|
||||
#include <AzCore/Debug/AssetTrackingTypes.h>
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
#include <AzCore/Memory/HphaSchema.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct AssetTreeNode;
|
||||
|
||||
// Per-thread data that needs to be stored.
|
||||
struct ThreadData
|
||||
{
|
||||
AZStd::vector<AssetTreeNodeBase*, AZStdAssetTrackingAllocator> m_currentAssetStack;
|
||||
};
|
||||
|
||||
// Access thread data through a virtual function to ensure that the same thread-local data is being shared across DLLs.
|
||||
// Otherwise, the thread_local variables are replicated across DLLs that link the AzCore library, and you'll get a
|
||||
// different version in each module.
|
||||
class ThreadDataProvider
|
||||
{
|
||||
public:
|
||||
virtual ThreadData& GetThreadData() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
class AssetTrackingImpl final :
|
||||
public ThreadDataProvider
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AssetTrackingImpl, "{01E2A099-3523-40BE-80E0-E0ADD861BEE1}");
|
||||
AZ_CLASS_ALLOCATOR(AssetTrackingImpl, OSAllocator, 0);
|
||||
|
||||
AssetTrackingImpl(AssetTreeBase* assetTree, AssetAllocationTableBase* allocationTable);
|
||||
~AssetTrackingImpl();
|
||||
|
||||
void AssetBegin(const char* id, const char* file, int line);
|
||||
void AssetAttach(void* otherAllocation, const char* file, int line);
|
||||
void AssetEnd();
|
||||
|
||||
ThreadData& GetThreadData() override;
|
||||
|
||||
private:
|
||||
static EnvironmentVariable<AssetTrackingImpl*>& GetEnvironmentVariable();
|
||||
static AssetTrackingImpl* GetSharedInstance();
|
||||
static ThreadData& GetSharedThreadData();
|
||||
|
||||
using PrimaryAssets = AZStd::unordered_map<AssetTrackingId, AssetPrimaryInfo, AZStd::hash<AssetTrackingId>, AZStd::equal_to<AssetTrackingId>, AZStdAssetTrackingAllocator>;
|
||||
using ThreadData = ThreadData;
|
||||
using mutex_type = AZStd::mutex;
|
||||
using lock_type = AZStd::lock_guard<mutex_type>;
|
||||
|
||||
mutex_type m_mutex;
|
||||
PrimaryAssets m_primaryAssets;
|
||||
AssetTreeNodeBase* m_assetRoot = nullptr;
|
||||
AssetAllocationTableBase* m_allocationTable = nullptr;
|
||||
bool m_performingAnalysis = false;
|
||||
|
||||
friend class AssetTracking;
|
||||
friend class AssetTracking::Scope;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AssetTrackingImpl methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AssetTrackingImpl::AssetTrackingImpl(AssetTreeBase* assetTree, AssetAllocationTableBase* allocationTable) :
|
||||
m_assetRoot(&assetTree->GetRoot()),
|
||||
m_allocationTable(allocationTable)
|
||||
{
|
||||
AZ_Assert(!GetSharedInstance(), "Only one AssetTrackingImpl can exist!");
|
||||
|
||||
GetEnvironmentVariable().Set(this);
|
||||
AllocatorManager::Instance().EnterProfilingMode();
|
||||
}
|
||||
|
||||
AssetTrackingImpl::~AssetTrackingImpl()
|
||||
{
|
||||
AllocatorManager::Instance().ExitProfilingMode();
|
||||
GetEnvironmentVariable().Reset();
|
||||
}
|
||||
|
||||
void AssetTrackingImpl::AssetBegin(const char* id, const char* file, int line)
|
||||
{
|
||||
// In the future it may be desirable to organize assets based on where in code the asset was entered into.
|
||||
// For now these are ignored.
|
||||
AZ_UNUSED(file);
|
||||
AZ_UNUSED(line);
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
AssetTrackingId assetId(id);
|
||||
auto& threadData = GetSharedThreadData();
|
||||
AssetTreeNodeBase* parentAsset = threadData.m_currentAssetStack.empty() ? nullptr : threadData.m_currentAssetStack.back();
|
||||
AssetTreeNodeBase* childAsset;
|
||||
AssetPrimaryInfo* assetPrimaryInfo;
|
||||
|
||||
if (!parentAsset)
|
||||
{
|
||||
parentAsset = m_assetRoot;
|
||||
}
|
||||
|
||||
{
|
||||
lock_type lock(m_mutex);
|
||||
|
||||
// Locate or create the primary record for this asset
|
||||
auto primaryItr = m_primaryAssets.find(assetId);
|
||||
|
||||
if (primaryItr != m_primaryAssets.end())
|
||||
{
|
||||
assetPrimaryInfo = &primaryItr->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto insertResult = m_primaryAssets.emplace(assetId, AssetPrimaryInfo());
|
||||
assetPrimaryInfo = &insertResult.first->second;
|
||||
assetPrimaryInfo->m_id = &insertResult.first->first;
|
||||
}
|
||||
|
||||
// Add this asset to the stack for this thread's context
|
||||
childAsset = parentAsset->FindOrAddChild(assetId, assetPrimaryInfo);
|
||||
}
|
||||
|
||||
threadData.m_currentAssetStack.push_back(childAsset);
|
||||
}
|
||||
|
||||
void AssetTrackingImpl::AssetAttach(void* otherAllocation, const char* file, int line)
|
||||
{
|
||||
AZ_UNUSED(file);
|
||||
AZ_UNUSED(line);
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
AssetTreeNodeBase* assetInfo = m_allocationTable->FindAllocation(otherAllocation);
|
||||
|
||||
// We will push back a nullptr if there is no asset, this is necessary to balance the call to AssetEnd()
|
||||
GetSharedThreadData().m_currentAssetStack.push_back(assetInfo);
|
||||
}
|
||||
|
||||
void AssetTrackingImpl::AssetEnd()
|
||||
{
|
||||
AZ_Assert(!GetSharedThreadData().m_currentAssetStack.empty(), "AssetEnd() called without matching AssetBegin() or AssetAttach. Use the AZ_ASSET_NAMED_SCOPE and AZ_ASSET_ATTACH_TO_SCOPE macros to avoid this!");
|
||||
GetSharedThreadData().m_currentAssetStack.pop_back();
|
||||
}
|
||||
|
||||
AssetTrackingImpl* AssetTrackingImpl::GetSharedInstance()
|
||||
{
|
||||
auto environmentVariable = GetEnvironmentVariable();
|
||||
|
||||
if(environmentVariable)
|
||||
{
|
||||
return *environmentVariable;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ThreadData& AssetTrackingImpl::GetSharedThreadData()
|
||||
{
|
||||
// Cast to the base type so our virtual call doesn't get optimized away. We require GetThreadData() to be executed in the same DLL every time.
|
||||
return static_cast<ThreadDataProvider*>(GetSharedInstance())->GetThreadData();
|
||||
}
|
||||
|
||||
AssetTrackingImpl::ThreadData& AssetTrackingImpl::GetThreadData()
|
||||
{
|
||||
static thread_local ThreadData* data = nullptr;
|
||||
static thread_local typename AZStd::aligned_storage_t<sizeof(ThreadData), alignof(ThreadData)> storage;
|
||||
|
||||
if (!data)
|
||||
{
|
||||
data = new (&storage) ThreadData;
|
||||
}
|
||||
|
||||
return *data;
|
||||
}
|
||||
|
||||
EnvironmentVariable<AssetTrackingImpl*>& AssetTrackingImpl::GetEnvironmentVariable()
|
||||
{
|
||||
static EnvironmentVariable<AssetTrackingImpl*> assetTrackingImpl = Environment::CreateVariable<AssetTrackingImpl*>(AzTypeInfo<AssetTrackingImpl*>::Name());
|
||||
|
||||
return assetTrackingImpl;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AssetTracking::Scope functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AssetTracking::Scope AssetTracking::Scope::ScopeFromAssetId(const char* file, int line, const char* fmt, ...)
|
||||
{
|
||||
if (auto impl = AssetTrackingImpl::GetSharedInstance())
|
||||
{
|
||||
static const int BUFFER_SIZE = 1024;
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
azvsnprintf(buffer, BUFFER_SIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
impl->AssetBegin(buffer, file, line);
|
||||
}
|
||||
|
||||
return Scope();
|
||||
}
|
||||
|
||||
AssetTracking::Scope AssetTracking::Scope::ScopeFromAttachment(void* attachTo, const char* file, int line)
|
||||
{
|
||||
if (auto impl = AssetTrackingImpl::GetSharedInstance())
|
||||
{
|
||||
impl->AssetAttach(attachTo, file, line);
|
||||
}
|
||||
|
||||
return Scope();
|
||||
}
|
||||
|
||||
AssetTracking::Scope::~Scope()
|
||||
{
|
||||
if (auto impl = AssetTrackingImpl::GetSharedInstance())
|
||||
{
|
||||
impl->AssetEnd();
|
||||
}
|
||||
}
|
||||
|
||||
AssetTracking::Scope::Scope()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AssetTracking functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AssetTracking::EnterScopeByAssetId(const char* file, int line, const char* fmt, ...)
|
||||
{
|
||||
if (auto impl = AssetTrackingImpl::GetSharedInstance())
|
||||
{
|
||||
static const int BUFFER_SIZE = 1024;
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
azvsnprintf(buffer, BUFFER_SIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
impl->AssetBegin(buffer, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetTracking::EnterScopeByAttachment(void* attachTo, const char* file, int line)
|
||||
{
|
||||
if (auto impl = AssetTrackingImpl::GetSharedInstance())
|
||||
{
|
||||
impl->AssetAttach(attachTo, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetTracking::ExitScope()
|
||||
{
|
||||
if (auto impl = AssetTrackingImpl::GetSharedInstance())
|
||||
{
|
||||
impl->AssetEnd();
|
||||
}
|
||||
}
|
||||
|
||||
const char* AssetTracking::GetDebugScope()
|
||||
{
|
||||
// Output debug information about the current asset scope in the current thread.
|
||||
// Do not use in production code.
|
||||
#ifndef RELEASE
|
||||
static const int BUFFER_SIZE = 1024;
|
||||
static char buffer[BUFFER_SIZE];
|
||||
const auto& assetStack = AssetTrackingImpl::GetSharedInstance()->GetThreadData().m_currentAssetStack;
|
||||
|
||||
if (assetStack.empty())
|
||||
{
|
||||
azsnprintf(buffer, BUFFER_SIZE, "<none>");
|
||||
}
|
||||
else
|
||||
{
|
||||
char* pos = buffer;
|
||||
for (auto itr = assetStack.rbegin(); itr != assetStack.rend(); ++itr)
|
||||
{
|
||||
pos += azsnprintf(pos, BUFFER_SIZE - (pos - buffer), "%s\n", (*itr)->GetAssetPrimaryInfo()->m_id->m_id.c_str());
|
||||
|
||||
if (pos >= buffer + BUFFER_SIZE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
AssetTracking::AssetTracking(AssetTreeBase* assetTree, AssetAllocationTableBase* allocationTable)
|
||||
{
|
||||
m_impl.reset(aznew AssetTrackingImpl(assetTree, allocationTable));
|
||||
}
|
||||
|
||||
AssetTracking::~AssetTracking()
|
||||
{
|
||||
}
|
||||
|
||||
AssetTreeNodeBase* AssetTracking::GetCurrentThreadAsset() const
|
||||
{
|
||||
const auto& assetStack = m_impl->GetThreadData().m_currentAssetStack;
|
||||
AssetTreeNodeBase* result = assetStack.empty() ? nullptr : assetStack.back();
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -1,131 +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/Memory/OSAllocator.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/EBus/Policies.h>
|
||||
|
||||
#ifndef AZ_TRACK_ASSET_SCOPES
|
||||
// You may manually uncomment this to enable asset tracking.
|
||||
//# define AZ_TRACK_ASSET_SCOPES
|
||||
#endif
|
||||
|
||||
#if !defined(AZ_TRACK_ASSET_SCOPES)
|
||||
// Default to enabling asset tracking when memory tracking is enabled
|
||||
# define AZ_TRACK_ASSET_SCOPES
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AZ_TRACK_ASSET_SCOPES
|
||||
#define AZ_ASSET_SCOPE_VARIABLE_NAME(line) AZ_JOIN(_az_assettracking_scope_, line)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Preferred macros to use at the top of a scope you want to to track asset memory for.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Creates a new scope with a name, usually the name of an asset being loaded. (This may be a format-string, e.g. "Foo: %s", bar.c_str())
|
||||
# define AZ_ASSET_NAMED_SCOPE(...) AZ::Debug::AssetTracking::Scope AZ_ASSET_SCOPE_VARIABLE_NAME(__LINE__) (AZ::Debug::AssetTracking::Scope::ScopeFromAssetId(__FILE__, __LINE__, __VA_ARGS__))
|
||||
|
||||
// Attempts to enter an existing scope that already owns some other allocation.
|
||||
# define AZ_ASSET_ATTACH_TO_SCOPE(other) AZ::Debug::AssetTracking::Scope AZ_ASSET_SCOPE_VARIABLE_NAME(__LINE__) (AZ::Debug::AssetTracking::Scope::ScopeFromAttachment((other), __FILE__, __LINE__))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Optional macros to manually enter and exit a scope.
|
||||
// It is the responsibility of the user to make sure every call to AZ_ASSET_ENTER_SCOPE_* is matched by a corresponding call to AZ_ASSET_EXIT_SCOPE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
# define AZ_ASSET_ENTER_SCOPE_BY_ASSET_ID(...) AZ::Debug::AssetTracking::EnterScopeByAssetId(__FILE__, __LINE__, __VA_ARGS__)
|
||||
# define AZ_ASSET_ENTER_SCOPE_BY_ATTACHMENT(other) AZ::Debug::AssetTracking::EnterScopeByAttachment((other), __FILE__, __LINE__)
|
||||
# define AZ_ASSET_EXIT_SCOPE AZ::Debug::AssetTracking::ExitScope()
|
||||
|
||||
#else
|
||||
# define AZ_ASSET_NAMED_SCOPE(...) (void)0
|
||||
# define AZ_ASSET_ATTACH_TO_SCOPE(other) (void)0
|
||||
|
||||
# define AZ_ASSET_ENTER_SCOPE_BY_ASSET_ID(...) (void)0
|
||||
# define AZ_ASSET_ENTER_SCOPE_BY_ATTACHMENT(other) (void)0
|
||||
# define AZ_ASSET_EXIT_SCOPE (void)0
|
||||
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
class AssetTrackingImpl;
|
||||
class AssetTreeBase;
|
||||
class AssetTreeNodeBase;
|
||||
class AssetAllocationTableBase;
|
||||
|
||||
class AssetTracking
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AssetTracking, "{D4335180-09A2-415A-8B50-9B734E7CE1E6}");
|
||||
AZ_CLASS_ALLOCATOR(AssetTracking, OSAllocator, 0);
|
||||
|
||||
// Provide RAII method for entering and exiting scopes.
|
||||
// Generally you will want to use the macros at the top of this file rather than instantiating this object directly.
|
||||
class Scope
|
||||
{
|
||||
public:
|
||||
static Scope ScopeFromAssetId(const char* file, int line, const char* fmt, ...);
|
||||
static Scope ScopeFromAttachment(void* attachTo, const char* file, int line);
|
||||
|
||||
Scope(Scope&&) = default;
|
||||
~Scope();
|
||||
|
||||
private:
|
||||
Scope();
|
||||
};
|
||||
|
||||
// Generally you will want to use the macros at the top of this file rather than calling these functions directly.
|
||||
static void EnterScopeByAssetId(const char* file, int line, const char* fmt, ...);
|
||||
static void EnterScopeByAttachment(void* attachTo, const char* file, int line);
|
||||
static void ExitScope();
|
||||
static const char* GetDebugScope();
|
||||
|
||||
AssetTracking(AssetTreeBase* assetTree, AssetAllocationTableBase* allocationTable);
|
||||
~AssetTracking();
|
||||
|
||||
AssetTreeNodeBase* GetCurrentThreadAsset() const;
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<AssetTrackingImpl> m_impl;
|
||||
};
|
||||
|
||||
// An EBus processing policy that attempts to attach to an existing scope before calling a handler.
|
||||
//
|
||||
// Use this on EBuses where you want the callees to track asset memory during their event handlers.
|
||||
// This will work so long as the callees were themselves allocated inside an existing asset scope.
|
||||
//
|
||||
// May be added to an existing EBus with the following code:
|
||||
// using EventProcessingPolicy = Debug::AssetTrackingEventProcessingPolicy;
|
||||
//
|
||||
template<typename Parent = EBusEventProcessingPolicy>
|
||||
struct AssetTrackingEventProcessingPolicy
|
||||
{
|
||||
template<class Results, class Function, class Interface, class... InputArgs>
|
||||
static void CallResult(Results& results, Function&& func, Interface&& iface, InputArgs&&... args)
|
||||
{
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(iface);
|
||||
Parent::CallResult(results, AZStd::forward<Function>(func), AZStd::forward<Interface>(iface), AZStd::forward<InputArgs>(args)...);
|
||||
}
|
||||
|
||||
template<class Function, class Interface, class... InputArgs>
|
||||
static void Call(Function&& func, Interface&& iface, InputArgs&&... args)
|
||||
{
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(iface);
|
||||
Parent::Call(AZStd::forward<Function>(func), AZStd::forward<Interface>(iface), AZStd::forward<InputArgs>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace AzFramework
|
||||
@@ -1,120 +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/Memory/HphaSchema.h>
|
||||
#include <AzCore/Memory/SimpleSchemaAllocator.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
struct AssetTrackingId;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// Declare hash specializations for types that need them; implementations will have to come after the classes are fully defined
|
||||
template<>
|
||||
struct hash<AZ::Debug::AssetTrackingId>
|
||||
{
|
||||
size_t operator()(const AZ::Debug::AssetTrackingId& id) const;
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class AssetTrackingImpl;
|
||||
|
||||
// Custom allocator for the Analyzer that doesn't go through profiling tools and cannot be overridden
|
||||
class AssetTrackingAllocator : public AZ::SimpleSchemaAllocator<AZ::HphaSchema, AZ::HphaSchema::Descriptor, false>
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AssetTrackingAllocator, "{F6C08E92-559C-4153-9620-6A8491F78F10}");
|
||||
|
||||
using Base = AZ::SimpleSchemaAllocator<AZ::HphaSchema, AZ::HphaSchema::Descriptor, false>;
|
||||
using Descriptor = Base::Descriptor;
|
||||
|
||||
AssetTrackingAllocator()
|
||||
: Base("AssetTrackingAllocator", "Allocator for the AssetTracking")
|
||||
{
|
||||
DisableOverriding();
|
||||
}
|
||||
};
|
||||
|
||||
using AZStdAssetTrackingAllocator = AZ::AZStdAlloc<AssetTrackingAllocator>;
|
||||
using AssetTrackingString = AZStd::basic_string<char, AZStd::char_traits<char>, AZStdAssetTrackingAllocator>;
|
||||
|
||||
template<typename Key, typename MappedType>
|
||||
using AssetTrackingMap = AZStd::unordered_map<Key, MappedType, AZStd::hash<Key>, AZStd::equal_to<Key>, AZStdAssetTrackingAllocator>;
|
||||
|
||||
|
||||
// ID for an asset that is hashable.
|
||||
// Currently only contains one string identifier, but we may want to store a more sophisticated ID in the future.
|
||||
struct AssetTrackingId
|
||||
{
|
||||
AssetTrackingId(const char* id) : m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const AssetTrackingId& other) const
|
||||
{
|
||||
return m_id == other.m_id;
|
||||
}
|
||||
|
||||
AssetTrackingString m_id;
|
||||
};
|
||||
|
||||
// Primary information about an asset.
|
||||
// Currently just contains the ID of the asset, but in the future may carry additional information about that asset (such as where in code it was initialized).
|
||||
struct AssetPrimaryInfo
|
||||
{
|
||||
const AssetTrackingId* m_id;
|
||||
};
|
||||
|
||||
// Base class for a node in the asset tree. Implemented by the template AssetTreeNode<>.
|
||||
class AssetTreeNodeBase
|
||||
{
|
||||
public:
|
||||
virtual ~AssetTreeNodeBase() = default;
|
||||
virtual const AssetPrimaryInfo* GetAssetPrimaryInfo() const = 0;
|
||||
virtual AssetTreeNodeBase* FindOrAddChild(const AssetTrackingId& id, const AssetPrimaryInfo* info) = 0;
|
||||
};
|
||||
|
||||
// Base class for an asset tree. Implemented by the template AssetTree<>.
|
||||
class AssetTreeBase
|
||||
{
|
||||
public:
|
||||
virtual ~AssetTreeBase() = default;
|
||||
virtual AssetTreeNodeBase& GetRoot() = 0;
|
||||
};
|
||||
|
||||
// Base class for an asset allocation table. Implemented by the template AssetAllocationTable<>.
|
||||
class AssetAllocationTableBase
|
||||
{
|
||||
public:
|
||||
virtual ~AssetAllocationTableBase() = default;
|
||||
virtual AssetTreeNodeBase* FindAllocation(void* ptr) const = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Hash functions for map support
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline size_t AZStd::hash<AZ::Debug::AssetTrackingId>::operator()(const AZ::Debug::AssetTrackingId& info) const
|
||||
{
|
||||
return AZStd::hash<AZ::Debug::AssetTrackingString>()(info.m_id);
|
||||
}
|
||||
|
||||
@@ -1,174 +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/AssetTrackingTypes.h>
|
||||
|
||||
#include <AzCore/std/containers/map.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
// A node in the current asset state tree.
|
||||
// Each thread maintains a stack of currently in-scope assets. As this stack changes the asset tree forms.
|
||||
// The same asset may appear in multiple places in the tree, e.g. if asset A is a common asset loaded by both asset B and asset C, the tree may look like:
|
||||
// Root -> B -> A
|
||||
// \--> C -> A
|
||||
template<typename AssetDataT>
|
||||
class AssetTreeNode : public AssetTreeNodeBase
|
||||
{
|
||||
public:
|
||||
AssetTreeNode(const AssetPrimaryInfo* primaryInfo = nullptr, AssetTreeNode* parent = nullptr) :
|
||||
m_primaryinfo(primaryInfo),
|
||||
m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
~AssetTreeNode() override = default;
|
||||
|
||||
const AssetPrimaryInfo* GetAssetPrimaryInfo() const override
|
||||
{
|
||||
return m_primaryinfo;
|
||||
}
|
||||
|
||||
AssetTreeNodeBase* FindOrAddChild(const AssetTrackingId& id, const AssetPrimaryInfo* info) override
|
||||
{
|
||||
AssetTreeNodeBase* result = nullptr;
|
||||
auto childItr = m_children.find(id);
|
||||
|
||||
if (childItr != m_children.end())
|
||||
{
|
||||
result = &childItr->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto childResult = m_children.emplace(id, AssetTreeNode(info, this));
|
||||
result = &childResult.first->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
using AssetMap = AssetTrackingMap<AssetTrackingId, AssetTreeNode>;
|
||||
|
||||
const AssetPrimaryInfo* m_primaryinfo;
|
||||
AssetTreeNode* m_parent;
|
||||
AssetMap m_children;
|
||||
AssetDataT m_data;
|
||||
};
|
||||
|
||||
template<typename AssetDataT>
|
||||
class AssetTree : public AssetTreeBase
|
||||
{
|
||||
public:
|
||||
~AssetTree() override = default;
|
||||
|
||||
AssetTreeNodeBase& GetRoot() override
|
||||
{
|
||||
return m_rootAssets;
|
||||
}
|
||||
|
||||
using NodeType = AssetTreeNode<AssetDataT>;
|
||||
|
||||
NodeType m_rootAssets;
|
||||
};
|
||||
|
||||
|
||||
template<typename AllocationDataT>
|
||||
struct AllocationRecord
|
||||
{
|
||||
AssetTreeNodeBase* m_asset;
|
||||
uint32_t m_size;
|
||||
AllocationDataT m_data;
|
||||
};
|
||||
|
||||
|
||||
template<typename AllocationDataT>
|
||||
class AllocationTable : public AssetAllocationTableBase
|
||||
{
|
||||
public:
|
||||
using RecordType = AllocationRecord<AllocationDataT>;
|
||||
using AllocationReverseMap = AZStd::map<void*, RecordType, AZStd::greater<void*>, AZStdAssetTrackingAllocator>;
|
||||
using mutex_type = AZStd::mutex;
|
||||
using lock_type = AZStd::lock_guard<mutex_type>;
|
||||
|
||||
AllocationTable(mutex_type& mutex) : m_mutex(mutex)
|
||||
{
|
||||
}
|
||||
~AllocationTable() override = default;
|
||||
|
||||
AssetTreeNodeBase* FindAllocation(void* ptr) const override
|
||||
{
|
||||
// Note that ptr is not guaranteed to have an exact entry in the map. For instance, ptr may point to a member of the original object that was allocated, or
|
||||
// ptr may be a different "this" pointer in the case of multiple inheritance.
|
||||
//
|
||||
// To solve this, we use lower_bound() and check to see if ptr falls in the range of the nearest allocation. Our map uses AZStd::greater instead of
|
||||
// AZStd::less as its sorting function, and thus sorts largest-to-smallest instead of smallest-to-largest. This causes lower_bound() to return the first
|
||||
// iterator that is not greater than otherAllocation, i.e. less than or equal to ptr.
|
||||
lock_type lock(m_mutex);
|
||||
auto itr = m_allocationTable.lower_bound(ptr);
|
||||
AssetTreeNodeBase* result = nullptr;
|
||||
|
||||
if (itr != m_allocationTable.end())
|
||||
{
|
||||
// Check if otherAllocation is within the size range of the allocation we found
|
||||
if (reinterpret_cast<uintptr_t>(ptr) <= reinterpret_cast<uintptr_t>(itr->first) + itr->second.m_size)
|
||||
{
|
||||
result = itr->second.m_asset;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReallocateAllocation(void* prevAddress, void* newAddress, size_t newByteSize)
|
||||
{
|
||||
lock_type lock(m_mutex);
|
||||
auto itr = m_allocationTable.find(prevAddress);
|
||||
|
||||
if (itr != m_allocationTable.end())
|
||||
{
|
||||
RecordType newAllocation = itr->second;
|
||||
newAllocation.m_size = (uint32_t)newByteSize;
|
||||
|
||||
m_allocationTable.erase(itr);
|
||||
m_allocationTable.emplace(newAddress, AZStd::move(newAllocation));
|
||||
}
|
||||
}
|
||||
|
||||
void ResizeAllocation(void* address, size_t newSize)
|
||||
{
|
||||
// Resize an existing allocation if we can find it
|
||||
lock_type lock(m_mutex);
|
||||
auto itr = m_allocationTable.find(address);
|
||||
|
||||
if (itr != m_allocationTable.end())
|
||||
{
|
||||
itr->second.m_size = (uint32_t)newSize;
|
||||
}
|
||||
}
|
||||
|
||||
AllocationReverseMap& Get()
|
||||
{
|
||||
return m_allocationTable;
|
||||
}
|
||||
|
||||
const AllocationReverseMap& Get() const
|
||||
{
|
||||
return m_allocationTable;
|
||||
}
|
||||
|
||||
private:
|
||||
AllocationReverseMap m_allocationTable;
|
||||
mutex_type& m_mutex;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,29 +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/Debug/EventTrace.h>
|
||||
#include <AzCore/Debug/EventTraceDrillerBus.h>
|
||||
#include <AzCore/std/time.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
EventTrace::ScopedSlice::ScopedSlice(const char* name, const char* category)
|
||||
: m_Name(name)
|
||||
, m_Category(category)
|
||||
, m_Time(AZStd::GetTimeNowMicroSecond())
|
||||
{
|
||||
}
|
||||
|
||||
EventTrace::ScopedSlice::~ScopedSlice()
|
||||
{
|
||||
EventTraceDrillerBus::TryQueueBroadcast(
|
||||
&EventTraceDrillerInterface::RecordSlice, m_Name, m_Category, AZStd::this_thread::get_id(), m_Time,
|
||||
(uint32_t)(AZStd::GetTimeNowMicroSecond() - m_Time));
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,43 +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/base.h>
|
||||
#include <AzCore/PlatformDef.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
struct thread_id;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
namespace EventTrace
|
||||
{
|
||||
class ScopedSlice
|
||||
{
|
||||
public:
|
||||
ScopedSlice(const char* name, const char* category);
|
||||
~ScopedSlice();
|
||||
|
||||
private:
|
||||
const char* m_Name;
|
||||
const char* m_Category;
|
||||
u64 m_Time;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define AZ_TRACE_METHOD_NAME_CATEGORY(name, category)
|
||||
#define AZ_TRACE_METHOD_NAME(name) AZ_TRACE_METHOD_NAME_CATEGORY(name, "")
|
||||
#define AZ_TRACE_METHOD() AZ_TRACE_METHOD_NAME(AZ_FUNCTION_SIGNATURE)
|
||||
@@ -1,159 +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/Debug/EventTraceDriller.h>
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
namespace Crc
|
||||
{
|
||||
constexpr u32 EventTraceDriller = AZ_CRC_CE("EventTraceDriller");
|
||||
constexpr u32 Slice = AZ_CRC_CE("Slice");
|
||||
constexpr u32 ThreadInfo = AZ_CRC_CE("ThreadInfo");
|
||||
constexpr u32 Name = AZ_CRC_CE("Name");
|
||||
constexpr u32 Category = AZ_CRC_CE("Category");
|
||||
constexpr u32 ThreadId = AZ_CRC_CE("ThreadId");
|
||||
constexpr u32 Timestamp = AZ_CRC_CE("Timestamp");
|
||||
constexpr u32 Duration = AZ_CRC_CE("Duration");
|
||||
constexpr u32 Instant = AZ_CRC_CE("Instant");
|
||||
}
|
||||
|
||||
EventTraceDriller::EventTraceDriller()
|
||||
{
|
||||
EventTraceDrillerSetupBus::Handler::BusConnect();
|
||||
AZStd::ThreadDrillerEventBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
EventTraceDriller::~EventTraceDriller()
|
||||
{
|
||||
AZStd::ThreadDrillerEventBus::Handler::BusDisconnect();
|
||||
EventTraceDrillerSetupBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void EventTraceDriller::Start(const Param* params, int numParams)
|
||||
{
|
||||
(void)params;
|
||||
(void)numParams;
|
||||
|
||||
EventTraceDrillerBus::Handler::BusConnect();
|
||||
TickBus::Handler::BusConnect();
|
||||
|
||||
EventTraceDrillerBus::AllowFunctionQueuing(true);
|
||||
}
|
||||
|
||||
void EventTraceDriller::Stop()
|
||||
{
|
||||
EventTraceDrillerBus::AllowFunctionQueuing(false);
|
||||
EventTraceDrillerBus::ClearQueuedEvents();
|
||||
|
||||
EventTraceDrillerBus::Handler::BusDisconnect();
|
||||
TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void EventTraceDriller::OnTick(float deltaTime, ScriptTimePoint time)
|
||||
{
|
||||
(void)deltaTime;
|
||||
(void)time;
|
||||
|
||||
AZ_TRACE_METHOD();
|
||||
RecordThreads();
|
||||
EventTraceDrillerBus::ExecuteQueuedEvents();
|
||||
}
|
||||
|
||||
void EventTraceDriller::SetThreadName(const AZStd::thread_id& id, const char* name)
|
||||
{
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_ThreadMutex);
|
||||
m_Threads[(size_t)id.m_id] = ThreadData{ name };
|
||||
}
|
||||
|
||||
void EventTraceDriller::OnThreadEnter(const AZStd::thread::id& id, const AZStd::thread_desc* desc)
|
||||
{
|
||||
if (desc && desc->m_name)
|
||||
{
|
||||
SetThreadName(id, desc->m_name);
|
||||
}
|
||||
}
|
||||
|
||||
void EventTraceDriller::OnThreadExit(const AZStd::thread::id& id)
|
||||
{
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_ThreadMutex);
|
||||
m_Threads.erase((size_t)id.m_id);
|
||||
}
|
||||
|
||||
void EventTraceDriller::RecordThreads()
|
||||
{
|
||||
if (!m_output || m_Threads.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Main bus mutex guards m_output.
|
||||
auto& context = EventTraceDrillerBus::GetOrCreateContext();
|
||||
|
||||
AZStd::scoped_lock<decltype(context.m_contextMutex), decltype(m_ThreadMutex)> lock(context.m_contextMutex, m_ThreadMutex);
|
||||
for (const auto& keyValue : m_Threads)
|
||||
{
|
||||
m_output->BeginTag(Crc::EventTraceDriller);
|
||||
m_output->BeginTag(Crc::ThreadInfo);
|
||||
m_output->Write(Crc::ThreadId, keyValue.first);
|
||||
m_output->Write(Crc::Name, keyValue.second.name);
|
||||
m_output->EndTag(Crc::ThreadInfo);
|
||||
m_output->EndTag(Crc::EventTraceDriller);
|
||||
}
|
||||
}
|
||||
|
||||
void EventTraceDriller::RecordSlice(
|
||||
const char* name,
|
||||
const char* category,
|
||||
const AZStd::thread_id threadId,
|
||||
AZ::u64 timestamp,
|
||||
AZ::u32 duration)
|
||||
{
|
||||
m_output->BeginTag(Crc::EventTraceDriller);
|
||||
m_output->BeginTag(Crc::Slice);
|
||||
m_output->Write(Crc::Name, name);
|
||||
m_output->Write(Crc::Category, category);
|
||||
m_output->Write(Crc::ThreadId, (size_t)threadId.m_id);
|
||||
m_output->Write(Crc::Timestamp, timestamp);
|
||||
m_output->Write(Crc::Duration, std::max(duration, 1u));
|
||||
m_output->EndTag(Crc::Slice);
|
||||
m_output->EndTag(Crc::EventTraceDriller);
|
||||
}
|
||||
|
||||
void EventTraceDriller::RecordInstantGlobal(
|
||||
const char* name,
|
||||
const char* category,
|
||||
AZ::u64 timestamp)
|
||||
{
|
||||
m_output->BeginTag(Crc::EventTraceDriller);
|
||||
m_output->BeginTag(Crc::Instant);
|
||||
m_output->Write(Crc::Name, name);
|
||||
m_output->Write(Crc::Category, category);
|
||||
m_output->Write(Crc::Timestamp, timestamp);
|
||||
m_output->EndTag(Crc::Instant);
|
||||
m_output->EndTag(Crc::EventTraceDriller);
|
||||
}
|
||||
|
||||
void EventTraceDriller::RecordInstantThread(
|
||||
const char* name,
|
||||
const char* category,
|
||||
const AZStd::thread_id threadId,
|
||||
AZ::u64 timestamp)
|
||||
{
|
||||
m_output->BeginTag(Crc::EventTraceDriller);
|
||||
m_output->BeginTag(Crc::Instant);
|
||||
m_output->Write(Crc::Name, name);
|
||||
m_output->Write(Crc::Category, category);
|
||||
m_output->Write(Crc::ThreadId, (size_t)threadId.m_id);
|
||||
m_output->Write(Crc::Timestamp, timestamp);
|
||||
m_output->EndTag(Crc::Instant);
|
||||
m_output->EndTag(Crc::EventTraceDriller);
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,87 +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/Driller/Driller.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/std/parallel/threadbus.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/Debug/EventTraceDrillerBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class EventTraceDriller
|
||||
: public Driller
|
||||
, public EventTraceDrillerBus::Handler
|
||||
, public EventTraceDrillerSetupBus::Handler
|
||||
, public AZStd::ThreadDrillerEventBus::Handler
|
||||
, public AZ::TickBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EventTraceDriller, OSAllocator, 0)
|
||||
|
||||
EventTraceDriller();
|
||||
virtual ~EventTraceDriller();
|
||||
|
||||
private:
|
||||
// Driller
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const char* GroupName() const override { return "SystemDrillers"; }
|
||||
const char* GetName() const override { return "EventTraceDriller"; }
|
||||
const char* GetDescription() const override { return "Handles timed events for a Chrome Tracing."; }
|
||||
void Start(const Param* params = NULL, int numParams = 0) override;
|
||||
void Stop() override;
|
||||
|
||||
// ThreadBus
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void OnThreadEnter(const AZStd::thread::id& id, const AZStd::thread_desc* desc) override;
|
||||
void OnThreadExit(const AZStd::thread::id& id) override;
|
||||
|
||||
// TickBus
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void OnTick(float deltaTime, ScriptTimePoint time) override;
|
||||
|
||||
// EventTraceDrillerSetupBus
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void SetThreadName(const AZStd::thread_id& threadId, const char* name) override;
|
||||
|
||||
// EventTraceDrillerBus
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void RecordSlice(
|
||||
const char* name,
|
||||
const char* category,
|
||||
const AZStd::thread_id threadId,
|
||||
AZ::u64 timestamp,
|
||||
AZ::u32 duration) override;
|
||||
|
||||
void RecordInstantGlobal(
|
||||
const char* name,
|
||||
const char* category,
|
||||
AZ::u64 timestamp) override;
|
||||
|
||||
void RecordInstantThread(
|
||||
const char* name,
|
||||
const char* category,
|
||||
const AZStd::thread_id threadId,
|
||||
AZ::u64 timestamp) override;
|
||||
|
||||
void RecordThreads();
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
AZStd::string name;
|
||||
};
|
||||
|
||||
AZStd::recursive_mutex m_ThreadMutex;
|
||||
AZStd::unordered_map<size_t, ThreadData, AZStd::hash<size_t>, AZStd::equal_to<size_t>, OSStdAllocator> m_Threads;
|
||||
};
|
||||
}
|
||||
} // namespace AZ
|
||||
@@ -1,81 +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/Driller/DrillerBus.h>
|
||||
#include <AzCore/std/time.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
struct thread_id;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class EventTraceDrillerInterface
|
||||
: public DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const bool EnableEventQueue = true;
|
||||
static const bool EventQueueingActiveByDefault = false;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~EventTraceDrillerInterface() {}
|
||||
|
||||
virtual void RecordSlice(
|
||||
const char* name,
|
||||
const char* category,
|
||||
const AZStd::thread_id threadId,
|
||||
AZ::u64 timestamp,
|
||||
AZ::u32 duration) = 0;
|
||||
|
||||
virtual void RecordInstantThread(
|
||||
const char* name,
|
||||
const char* category,
|
||||
const AZStd::thread_id threadId,
|
||||
AZ::u64 timestamp) = 0;
|
||||
|
||||
virtual void RecordInstantGlobal(
|
||||
const char* name,
|
||||
const char* category,
|
||||
AZ::u64 timestamp) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<EventTraceDrillerInterface> EventTraceDrillerBus;
|
||||
|
||||
class EventTraceDrillerSetupInterface
|
||||
: public DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~EventTraceDrillerSetupInterface() {}
|
||||
|
||||
virtual void SetThreadName(const AZStd::thread_id& threadId, const char* name) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<EventTraceDrillerSetupInterface> EventTraceDrillerSetupBus;
|
||||
}
|
||||
}
|
||||
|
||||
#define AZ_TRACE_INSTANT_GLOBAL_CATEGORY(name, category) \
|
||||
EBUS_QUEUE_EVENT(AZ::Debug::EventTraceDrillerBus, RecordInstantGlobal, name, category, AZStd::GetTimeNowMicroSecond())
|
||||
#define AZ_TRACE_INSTANT_GLOBAL(name) AZ_TRACE_INSTANT_GLOBAL_CATEGORY(name, "")
|
||||
|
||||
#define AZ_TRACE_INSTANT_THREAD_CATEGORY(name, category) \
|
||||
EBUS_QUEUE_EVENT(AZ::Debug::EventTraceDrillerBus, RecordInstantThread, name, category, AZStd::this_thread::get_id(), AZStd::GetTimeNowMicroSecond())
|
||||
#define AZ_TRACE_INSTANT_THREAD(name) AZ_TRACE_INSTANT_THREAD_CATEGORY(name, "")
|
||||
@@ -8,7 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef AZ_PROFILE_MEMORY_ALLOC
|
||||
// No other profiler has defined the performance markers AZ_PROFILE_MEMORY_ALLOC (and friends), fall back to a Driller implementation (currently empty)
|
||||
// No other profiler has defined the performance markers AZ_PROFILE_MEMORY_ALLOC (and friends), fall back to current implementation (empty)
|
||||
# define AZ_PROFILE_MEMORY_ALLOC(category, address, size, context)
|
||||
# define AZ_PROFILE_MEMORY_ALLOC_EX(category, filename, lineNumber, address, size, context)
|
||||
# define AZ_PROFILE_MEMORY_FREE(category, address)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/Debug/TraceMessagesDrillerBus.h>
|
||||
#include <AzCore/Debug/IEventLogger.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
@@ -276,8 +275,6 @@ namespace AZ::Debug
|
||||
logger->Flush(); // Flush as an assert may indicate a crash is imminent.
|
||||
}
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnPreAssert, fileName, line, funcName, message);
|
||||
|
||||
TraceMessageResult result;
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnPreAssert, fileName, line, funcName, message);
|
||||
|
||||
@@ -302,7 +299,6 @@ namespace AZ::Debug
|
||||
azstrcat(message, g_maxMessageLength, "\n");
|
||||
Output(g_dbgSystemWnd, message);
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnAssert, message);
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnAssert, message);
|
||||
if (result.m_value)
|
||||
{
|
||||
@@ -405,8 +401,6 @@ namespace AZ::Debug
|
||||
logger->RecordStringEvent(ErrorEventId, message);
|
||||
}
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnPreError, window, fileName, line, funcName, message);
|
||||
|
||||
TraceMessageResult result;
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnPreError, window, fileName, line, funcName, message);
|
||||
if (result.m_value)
|
||||
@@ -421,7 +415,6 @@ namespace AZ::Debug
|
||||
azstrcat(message, g_maxMessageLength, "\n");
|
||||
Output(window, message);
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnError, window, message);
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnError, window, message);
|
||||
Output(window, "==================================================================\n");
|
||||
if (result.m_value)
|
||||
@@ -457,8 +450,6 @@ namespace AZ::Debug
|
||||
logger->RecordStringEvent(WarningEventId, message);
|
||||
}
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnPreWarning, window, fileName, line, funcName, message);
|
||||
|
||||
TraceMessageResult result;
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnPreWarning, window, fileName, line, funcName, message);
|
||||
if (result.m_value)
|
||||
@@ -472,7 +463,6 @@ namespace AZ::Debug
|
||||
azstrcat(message, g_maxMessageLength, "\n");
|
||||
Output(window, message);
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnWarning, window, message);
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnWarning, window, message);
|
||||
Output(window, "==================================================================\n");
|
||||
}
|
||||
@@ -501,8 +491,6 @@ namespace AZ::Debug
|
||||
logger->RecordStringEvent(PrintfEventId, message);
|
||||
}
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnPrintf, window, message);
|
||||
|
||||
TraceMessageResult result;
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnPrintf, window, message);
|
||||
if (result.m_value)
|
||||
@@ -531,7 +519,6 @@ namespace AZ::Debug
|
||||
// only call into Ebusses if we are not in a recursive-exception situation as that
|
||||
// would likely just lead to even more exceptions.
|
||||
|
||||
EBUS_EVENT(TraceMessageDrillerBus, OnOutput, window, message);
|
||||
TraceMessageResult result;
|
||||
EBUS_EVENT_RESULT(result, TraceMessageBus, OnOutput, window, message);
|
||||
if (result.m_value)
|
||||
|
||||
@@ -1,99 +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/Debug/TraceMessagesDriller.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
//=========================================================================
|
||||
// Start
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void TraceMessagesDriller::Start(const Param* params, int numParams)
|
||||
{
|
||||
(void)params;
|
||||
(void)numParams;
|
||||
BusConnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Stop
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void TraceMessagesDriller::Stop()
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnAssert
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void TraceMessagesDriller::OnAssert(const char* message)
|
||||
{
|
||||
// Not sure if we can really capture assert since the code will stop executing very soon.
|
||||
m_output->BeginTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
m_output->Write(AZ_CRC_CE("OnAssert"), message);
|
||||
m_output->EndTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnException
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void TraceMessagesDriller::OnException(const char* message)
|
||||
{
|
||||
// Not sure if we can really capture exception since the code will stop executing very soon.
|
||||
m_output->BeginTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
m_output->Write(AZ_CRC_CE("OnException"), message);
|
||||
m_output->EndTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnError
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void TraceMessagesDriller::OnError(const char* window, const char* message)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
m_output->BeginTag(AZ_CRC_CE("OnError"));
|
||||
m_output->Write(AZ_CRC_CE("Window"), window);
|
||||
m_output->Write(AZ_CRC_CE("Message"), message);
|
||||
m_output->EndTag(AZ_CRC_CE("OnError"));
|
||||
m_output->EndTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnWarning
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void TraceMessagesDriller::OnWarning(const char* window, const char* message)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
m_output->BeginTag(AZ_CRC_CE("OnWarning"));
|
||||
m_output->Write(AZ_CRC_CE("Window"), window);
|
||||
m_output->Write(AZ_CRC_CE("Message"), message);
|
||||
m_output->EndTag(AZ_CRC_CE("OnWarning"));
|
||||
m_output->EndTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnPrintf
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void TraceMessagesDriller::OnPrintf(const char* window, const char* message)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
m_output->BeginTag(AZ_CRC_CE("OnPrintf"));
|
||||
m_output->Write(AZ_CRC_CE("Window"), window);
|
||||
m_output->Write(AZ_CRC_CE("Message"), message);
|
||||
m_output->EndTag(AZ_CRC_CE("OnPrintf"));
|
||||
m_output->EndTag(AZ_CRC_CE("TraceMessagesDriller"));
|
||||
}
|
||||
} // 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Debug/TraceMessagesDrillerBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
/**
|
||||
* Trace messages driller class
|
||||
*/
|
||||
class TraceMessagesDriller
|
||||
: public Driller
|
||||
, public TraceMessageDrillerBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(TraceMessagesDriller, OSAllocator, 0)
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller
|
||||
const char* GroupName() const override { return "SystemDrillers"; }
|
||||
const char* GetName() const override { return "TraceMessagesDriller"; }
|
||||
const char* GetDescription() const override { return "Handles all system messages like Assert, Exception, Error, Warning, Printf, etc."; }
|
||||
void Start(const Param* params = NULL, int numParams = 0) override;
|
||||
void Stop() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TraceMessagesDrillerBus
|
||||
/// Triggered when a AZ_Assert failed. This is terminating event! (the code will break, crash).
|
||||
void OnAssert(const char* message) override;
|
||||
void OnException(const char* message) override;
|
||||
void OnError(const char* window, const char* message) override;
|
||||
void OnWarning(const char* window, const char* message) override;
|
||||
void OnPrintf(const char* window, const char* message) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
@@ -1,53 +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/Driller/DrillerBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
/**
|
||||
* Trace messages event handle.
|
||||
* All messages are optional (they have default implementation) and you can handle only one at a time.
|
||||
* Driller messages are similar to TraceMessages, but do not provide a return value,
|
||||
* as we only care about collecting driller messages, not operating on them.
|
||||
*
|
||||
* We use a driller bus so all messages are sending in exclusive matter no other driller messages
|
||||
* can be triggered at that moment, so we already preserve the calling order. You can assume
|
||||
* all access code in the driller framework in guarded. You can manually lock the driller mutex are you
|
||||
* use by using \ref AZ::Debug::DrillerEBusMutex.
|
||||
*/
|
||||
class TraceMessageDrillerEvents
|
||||
: public DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~TraceMessageDrillerEvents() {}
|
||||
|
||||
/// Triggered when a AZ_Assert failed. This is terminating event! (the code will break, crash).
|
||||
virtual void OnPreAssert(const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) {}
|
||||
virtual void OnAssert(const char* /*message*/) {}
|
||||
virtual void OnException(const char* /*message*/) {}
|
||||
virtual void OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) {}
|
||||
virtual void OnError(const char* /*window*/, const char* /*message*/) {}
|
||||
virtual void OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) {}
|
||||
virtual void OnWarning(const char* /*window*/, const char* /*message*/) {}
|
||||
virtual void OnPrintf(const char* /*window*/, const char* /*message*/) {}
|
||||
/**
|
||||
* All trace functions you output to anything. So if you want to handle all the output this is the place.
|
||||
* You are not given the choice to disable the system output as if you listen at that level you can't make
|
||||
* that decision. Otherwise we can trigger an assert without even one line of message send to the console/debugger.
|
||||
*/
|
||||
virtual void OnOutput(const char* /*window*/, const char* /*message*/) {}
|
||||
};
|
||||
|
||||
typedef AZ::EBus<TraceMessageDrillerEvents> TraceMessageDrillerBus;
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
@@ -1,125 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_DRILLER_DEFAULT_STRING_POOL_H
|
||||
#define AZCORE_DRILLER_DEFAULT_STRING_POOL_H
|
||||
|
||||
#include <AzCore/Driller/Stream.h>
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
template<class Key, class Mapped>
|
||||
struct unordered_map
|
||||
{
|
||||
typedef AZStd::unordered_map<Key, Mapped, AZStd::hash<Key>, AZStd::equal_to<Key>, OSStdAllocator> type;
|
||||
};
|
||||
|
||||
template<class Key>
|
||||
struct unordered_set
|
||||
{
|
||||
typedef AZStd::unordered_set<Key, AZStd::hash<Key>, AZStd::equal_to<Key>, OSStdAllocator> type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default implementation of a string pool.
|
||||
*/
|
||||
class DrillerDefaultStringPool
|
||||
: public DrillerStringPool
|
||||
{
|
||||
public:
|
||||
virtual ~DrillerDefaultStringPool()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
typedef unordered_map<AZ::u32, const char*>::type CrcToStringMapType;
|
||||
typedef unordered_set<const char*>::type OwnedStringsMapType;
|
||||
|
||||
/**
|
||||
* Add a copy of the string to the pool. If we return true the string was added otherwise it was already in the bool.
|
||||
* In both cases the crc32 of the string and the pointer to the shared copy is returned (optional for poolStringAddress)!
|
||||
*/
|
||||
virtual bool InsertCopy(const char* string, unsigned int length, AZ::u32& crc32, const char** poolStringAddress = nullptr)
|
||||
{
|
||||
crc32 = AZ::Crc32(string, length);
|
||||
CrcToStringMapType::pair_iter_bool insertIt = m_crcToStringMap.insert_key(crc32);
|
||||
if (insertIt.second)
|
||||
{
|
||||
char* newString = reinterpret_cast<char*>(azmalloc(length + 1, 1, AZ::OSAllocator));
|
||||
memcpy(newString, string, length);
|
||||
newString[length] = '\0'; // terminate
|
||||
m_ownedStrings.insert(newString);
|
||||
insertIt.first->second = newString;
|
||||
}
|
||||
if (poolStringAddress)
|
||||
{
|
||||
*poolStringAddress = insertIt.first->second;
|
||||
}
|
||||
return insertIt.second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as the InsertCopy above without actually coping the string into the pool. The pool assumes that
|
||||
* none of the strings added to the pool will be deleted.
|
||||
*/
|
||||
virtual bool Insert(const char* string, unsigned int length, AZ::u32& crc32)
|
||||
{
|
||||
crc32 = AZ::Crc32(string, length);
|
||||
return m_crcToStringMap.insert(AZStd::make_pair(crc32, string)).second;
|
||||
}
|
||||
|
||||
/// Finds a string in the pool by crc32.
|
||||
virtual const char* Find(AZ::u32 crc32)
|
||||
{
|
||||
CrcToStringMapType::iterator it = m_crcToStringMap.find(crc32);
|
||||
if (it != m_crcToStringMap.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual void Erase(AZ::u32 crc32)
|
||||
{
|
||||
CrcToStringMapType::iterator it = m_crcToStringMap.find(crc32);
|
||||
if (it != m_crcToStringMap.end())
|
||||
{
|
||||
OwnedStringsMapType::iterator ownerIt = m_ownedStrings.find(it->second);
|
||||
if (ownerIt != m_ownedStrings.end())
|
||||
{
|
||||
azfree(const_cast<char*>(it->second), AZ::OSAllocator);
|
||||
m_ownedStrings.erase(ownerIt);
|
||||
}
|
||||
m_crcToStringMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Reset()
|
||||
{
|
||||
for (OwnedStringsMapType::iterator it = m_ownedStrings.begin(); it != m_ownedStrings.end(); ++it)
|
||||
{
|
||||
azfree(const_cast<char*>(*it), AZ::OSAllocator);
|
||||
}
|
||||
m_crcToStringMap.clear();
|
||||
m_ownedStrings.clear();
|
||||
}
|
||||
protected:
|
||||
CrcToStringMapType m_crcToStringMap;
|
||||
OwnedStringsMapType m_ownedStrings;
|
||||
};
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_DRILLER_DEFAULT_STRING_POOL_H
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,301 +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/Driller/Driller.h>
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/parallel/lock.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class DrillerManagerImpl
|
||||
: public DrillerManager
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerManagerImpl, OSAllocator, 0);
|
||||
|
||||
using SessionListType = forward_list<DrillerSession>::type;
|
||||
SessionListType m_sessions;
|
||||
using DrillerArrayType = vector<Driller*>::type;
|
||||
DrillerArrayType m_drillers;
|
||||
|
||||
~DrillerManagerImpl() override;
|
||||
|
||||
void Register(Driller* factory) override;
|
||||
void Unregister(Driller* factory) override;
|
||||
|
||||
void FrameUpdate() override;
|
||||
|
||||
DrillerSession* Start(DrillerOutputStream& output, const DrillerListType& drillerList, int numFrames = -1) override;
|
||||
void Stop(DrillerSession* session) override;
|
||||
|
||||
int GetNumDrillers() const override { return static_cast<int>(m_drillers.size()); }
|
||||
Driller* GetDriller(int index) override { return m_drillers[index]; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller
|
||||
|
||||
//=========================================================================
|
||||
// Register
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
AZ::u32 Driller::GetId() const
|
||||
{
|
||||
return AZ::Crc32(GetName());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller Manager
|
||||
|
||||
//=========================================================================
|
||||
// Register
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
DrillerManager* DrillerManager::Create(/*const Descriptor& desc*/)
|
||||
{
|
||||
const bool createAllocator = !AZ::AllocatorInstance<OSAllocator>::IsReady();
|
||||
if (createAllocator)
|
||||
{
|
||||
AZ::AllocatorInstance<OSAllocator>::Create();
|
||||
}
|
||||
|
||||
DrillerManagerImpl* impl = aznew DrillerManagerImpl;
|
||||
impl->m_ownsOSAllocator = createAllocator;
|
||||
return impl;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Register
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
void DrillerManager::Destroy(DrillerManager* manager)
|
||||
{
|
||||
const bool allocatorCreated = manager->m_ownsOSAllocator;
|
||||
delete manager;
|
||||
if (allocatorCreated)
|
||||
{
|
||||
AZ::AllocatorInstance<OSAllocator>::Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerManagerImpl
|
||||
|
||||
//=========================================================================
|
||||
// ~DrillerManagerImpl
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
DrillerManagerImpl::~DrillerManagerImpl()
|
||||
{
|
||||
while (!m_sessions.empty())
|
||||
{
|
||||
Stop(&m_sessions.front());
|
||||
}
|
||||
|
||||
while (!m_drillers.empty())
|
||||
{
|
||||
Driller* driller = m_drillers[0];
|
||||
Unregister(driller);
|
||||
delete driller;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Register
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerManagerImpl::Register(Driller* driller)
|
||||
{
|
||||
AZ_Assert(driller, "You must provide a valid factory!");
|
||||
for (size_t i = 0; i < m_drillers.size(); ++i)
|
||||
{
|
||||
if (m_drillers[i]->GetId() == driller->GetId())
|
||||
{
|
||||
AZ_Error("Debug", false, "Driller with id %08x has already been registered! You can't have two factory instances for the same driller type", driller->GetId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_drillers.push_back(driller);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Unregister
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerManagerImpl::Unregister(Driller* driller)
|
||||
{
|
||||
AZ_Assert(driller, "You must provide a valid factory!");
|
||||
for (DrillerArrayType::iterator iter = m_drillers.begin(); iter != m_drillers.end(); ++iter)
|
||||
{
|
||||
if ((*iter)->GetId() == driller->GetId())
|
||||
{
|
||||
m_drillers.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Error("Debug", false, "Failed to find driller factory with id %08x", driller->GetId());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// FrameUpdate
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerManagerImpl::FrameUpdate()
|
||||
{
|
||||
if (m_sessions.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::lock_guard<DrillerEBusMutex::MutexType> lock(DrillerEBusMutex::GetMutex()); ///< Make sure no driller is writing to the stream
|
||||
for (SessionListType::iterator sessionIter = m_sessions.begin(); sessionIter != m_sessions.end(); )
|
||||
{
|
||||
DrillerSession& s = *sessionIter;
|
||||
|
||||
// tick the drillers directly if they care.
|
||||
for (size_t i = 0; i < s.drillers.size(); ++i)
|
||||
{
|
||||
s.drillers[i]->Update();
|
||||
}
|
||||
|
||||
s.output->EndTag(AZ_CRC("Frame", 0xb5f83ccd));
|
||||
|
||||
s.output->OnEndOfFrame();
|
||||
|
||||
s.curFrame++;
|
||||
|
||||
if (s.numFrames != -1)
|
||||
{
|
||||
if (s.curFrame == s.numFrames)
|
||||
{
|
||||
Stop(&s);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
s.output->BeginTag(AZ_CRC("Frame", 0xb5f83ccd));
|
||||
s.output->Write(AZ_CRC("FrameNum", 0x85a1a919), s.curFrame);
|
||||
|
||||
++sessionIter;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Start
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
DrillerSession*
|
||||
DrillerManagerImpl::Start(DrillerOutputStream& output, const DrillerListType& drillerList, int numFrames)
|
||||
{
|
||||
if (drillerList.empty())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_sessions.push_back();
|
||||
DrillerSession& s = m_sessions.back();
|
||||
s.curFrame = 0;
|
||||
s.numFrames = numFrames;
|
||||
s.output = &output;
|
||||
|
||||
s.output->WriteHeader(); // first write the header in the stream
|
||||
|
||||
s.output->BeginTag(AZ_CRC("StartData", 0xecf3f53f));
|
||||
s.output->Write(AZ_CRC("Platform", 0x3952d0cb), (unsigned int)g_currentPlatform);
|
||||
for (DrillerListType::const_iterator iDriller = drillerList.begin(); iDriller != drillerList.end(); ++iDriller)
|
||||
{
|
||||
const DrillerInfo& di = *iDriller;
|
||||
s.output->BeginTag(AZ_CRC("Driller", 0xa6e1fb73));
|
||||
s.output->Write(AZ_CRC("Name", 0x5e237e06), di.id);
|
||||
for (int iParam = 0; iParam < (int)di.params.size(); ++iParam)
|
||||
{
|
||||
s.output->BeginTag(AZ_CRC("Param", 0xa4fa7c89));
|
||||
s.output->Write(AZ_CRC("Name", 0x5e237e06), di.params[iParam].name);
|
||||
s.output->Write(AZ_CRC("Description", 0x6de44026), di.params[iParam].desc);
|
||||
s.output->Write(AZ_CRC("Type", 0x8cde5729), di.params[iParam].type);
|
||||
s.output->Write(AZ_CRC("Value", 0x1d775834), di.params[iParam].value);
|
||||
s.output->EndTag(AZ_CRC("Param", 0xa4fa7c89));
|
||||
}
|
||||
s.output->EndTag(AZ_CRC("Driller", 0xa6e1fb73));
|
||||
}
|
||||
s.output->EndTag(AZ_CRC("StartData", 0xecf3f53f));
|
||||
|
||||
s.output->BeginTag(AZ_CRC("Frame", 0xb5f83ccd));
|
||||
s.output->Write(AZ_CRC("FrameNum", 0x85a1a919), s.curFrame);
|
||||
|
||||
{
|
||||
AZStd::lock_guard<DrillerEBusMutex::MutexType> lock(DrillerEBusMutex::GetMutex()); ///< Make sure no driller is writing to the stream
|
||||
for (DrillerListType::const_iterator iDriller = drillerList.begin(); iDriller != drillerList.end(); ++iDriller)
|
||||
{
|
||||
Driller* driller = nullptr;
|
||||
const DrillerInfo& di = *iDriller;
|
||||
for (size_t iDesc = 0; iDesc < m_drillers.size(); ++iDesc)
|
||||
{
|
||||
if (m_drillers[iDesc]->GetId() == di.id)
|
||||
{
|
||||
driller = m_drillers[iDesc];
|
||||
AZ_Assert(driller->m_output == nullptr, "Driller with id %08x is already have an output stream %p (currently we support only 1 at a time)", di.id, driller->m_output);
|
||||
driller->m_output = &output;
|
||||
driller->Start(di.params.data(), static_cast<unsigned int>(di.params.size()));
|
||||
s.drillers.push_back(driller);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AZ_Warning("Driller", driller != nullptr, "We can't start a driller with id %d!", di.id);
|
||||
}
|
||||
}
|
||||
return &s;
|
||||
}
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// Stop
|
||||
// [3/17/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerManagerImpl::Stop(DrillerSession* session)
|
||||
{
|
||||
SessionListType::iterator iter;
|
||||
for (iter = m_sessions.begin(); iter != m_sessions.end(); ++iter)
|
||||
{
|
||||
if (&*iter == session)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Assert(iter != m_sessions.end(), "We did not find session ID 0x%08x in the list!", session);
|
||||
if (iter != m_sessions.end())
|
||||
{
|
||||
DrillerSession& s = *session;
|
||||
|
||||
{
|
||||
AZStd::lock_guard<DrillerEBusMutex::MutexType> lock(DrillerEBusMutex::GetMutex());
|
||||
for (size_t i = 0; i < s.drillers.size(); ++i)
|
||||
{
|
||||
s.drillers[i]->Stop();
|
||||
s.drillers[i]->m_output = nullptr;
|
||||
}
|
||||
}
|
||||
s.output->EndTag(AZ_CRC("Frame", 0xb5f83ccd));
|
||||
m_sessions.erase(iter);
|
||||
}
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,141 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_DRILLER_H
|
||||
#define AZCORE_DRILLER_H
|
||||
|
||||
#include <AzCore/Driller/Stream.h>
|
||||
namespace AZStd
|
||||
{
|
||||
class mutex;
|
||||
}
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class DrillerOutputStream;
|
||||
|
||||
/**
|
||||
* Driller base class. Every driller should inherit from this class.
|
||||
* When a driller is need to start outputting data
|
||||
* the DrillerManager will call Driller::Start() so the driller
|
||||
* can output the initial state for all reported entities.
|
||||
* The same applies for the Stop.
|
||||
* Depending on the type of your driller you might choose to collect state
|
||||
* even before the driller has started. This of course should be a fast as
|
||||
* possible, as we don't want to burden engine systems and it's highly recommended
|
||||
* that you use configuration parameters to change that behavior as not all drillers
|
||||
* are used on a daily basis.
|
||||
* All drillers should use DebugAllocators (AZ_CLASS_ALLOCATOR(Driller,OSAllocator,0))
|
||||
* and they should use 'aznew' to create one, as by default if you don't unregister a
|
||||
* a driller, the manager will use "delete" to delete them.
|
||||
*
|
||||
* IMPORTANT: Driller systems works OUTSIDE engine systems, you should NOT use SystemAllocator or any other engine systems
|
||||
* as they might be drilled or not available at the moment.
|
||||
*/
|
||||
class Driller
|
||||
{
|
||||
friend class DrillerManagerImpl;
|
||||
|
||||
public:
|
||||
struct Param
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
PT_BOOL,
|
||||
PT_INT,
|
||||
PT_FLOAT
|
||||
};
|
||||
const char* desc;
|
||||
u32 name;
|
||||
int type;
|
||||
int value;
|
||||
};
|
||||
|
||||
Driller()
|
||||
: m_output(NULL) {}
|
||||
virtual ~Driller() {}
|
||||
|
||||
/// Returns the driller ID Crc32 of the name (Crc32(GetName())
|
||||
AZ::u32 GetId() const;
|
||||
/// Driller group name, used only for organizational purpose
|
||||
virtual const char* GroupName() const = 0;
|
||||
/// Unique name of the Driller, driller ID is the Crc of the name
|
||||
virtual const char* GetName() const = 0;
|
||||
virtual const char* GetDescription() const = 0;
|
||||
// @{ Managing the list of supported driller parameters.
|
||||
virtual int GetNumParams() const { return 0; }
|
||||
virtual const Param* GetParam(int index) const { (void)index; return NULL; }
|
||||
|
||||
protected:
|
||||
Driller& operator=(const Driller&);
|
||||
|
||||
/// Called by DrillerManager
|
||||
virtual void Start(const Param* params = NULL, int numParams = 0) { (void)params; (void)numParams; }
|
||||
/// Called by DrillerManager
|
||||
virtual void Stop() {}
|
||||
/// Called every frame by DrillerManger (while the driller is started)
|
||||
virtual void Update() {}
|
||||
|
||||
DrillerOutputStream* m_output; ///< Session output stream.
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores the information while an active
|
||||
* driller(s) session is running.
|
||||
*/
|
||||
struct DrillerSession
|
||||
{
|
||||
int numFrames;
|
||||
int curFrame;
|
||||
typedef vector<Driller*>::type DrillerArrayType;
|
||||
DrillerArrayType drillers;
|
||||
DrillerOutputStream* output;
|
||||
};
|
||||
|
||||
/**
|
||||
* Driller manager will manage all active driller sessions and driller factories. Generally you will never
|
||||
* need more than one driller manger.
|
||||
* IMPORTANT: Driller systems works OUTSIDE engine systems, you should NOT use SystemAllocator or any other engine systems
|
||||
* as they might be drilled or not available at the moment.
|
||||
*/
|
||||
class DrillerManager
|
||||
{
|
||||
friend class DrillerRemoteServer;
|
||||
public:
|
||||
struct DrillerInfo
|
||||
{
|
||||
AZ::u32 id;
|
||||
vector<Driller::Param>::type params;
|
||||
};
|
||||
typedef forward_list<DrillerInfo>::type DrillerListType;
|
||||
|
||||
virtual ~DrillerManager() {}
|
||||
|
||||
static DrillerManager* Create(/*const Descriptor& desc*/);
|
||||
static void Destroy(DrillerManager* manager);
|
||||
|
||||
virtual void Register(Driller* driller) = 0;
|
||||
virtual void Unregister(Driller* driller) = 0;
|
||||
|
||||
virtual void FrameUpdate() = 0;
|
||||
|
||||
virtual DrillerSession* Start(DrillerOutputStream& output, const DrillerListType& drillerList, int numFrames = -1) = 0;
|
||||
virtual void Stop(DrillerSession* session) = 0;
|
||||
|
||||
virtual int GetNumDrillers() const = 0;
|
||||
virtual Driller* GetDriller(int index) = 0;
|
||||
|
||||
private:
|
||||
// If the manager created the allocator, it should destroy it when it gets destroyed
|
||||
bool m_ownsOSAllocator = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AZCORE_DRILLER_H
|
||||
#pragma once
|
||||
@@ -1,65 +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/Driller/DrillerBus.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Globals
|
||||
// We need to synchronize all driller evens, so we have proper order, and access to the data
|
||||
// We use a global mutex which should be used for all driller operations.
|
||||
// The mutex is held in an environment variable so it works across DLLs.
|
||||
EnvironmentVariable<AZStd::recursive_mutex> s_drillerGlobalMutex;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// lock
|
||||
// [4/11/2011]
|
||||
//=========================================================================
|
||||
void DrillerEBusMutex::lock()
|
||||
{
|
||||
GetMutex().lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// try_lock
|
||||
// [4/11/2011]
|
||||
//=========================================================================
|
||||
bool DrillerEBusMutex::try_lock()
|
||||
{
|
||||
return GetMutex().try_lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// unlock
|
||||
// [4/11/2011]
|
||||
//=========================================================================
|
||||
void DrillerEBusMutex::unlock()
|
||||
{
|
||||
GetMutex().unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// unlock
|
||||
// [4/11/2011]
|
||||
//=========================================================================
|
||||
AZStd::recursive_mutex& DrillerEBusMutex::GetMutex()
|
||||
{
|
||||
if (!s_drillerGlobalMutex)
|
||||
{
|
||||
s_drillerGlobalMutex = Environment::CreateVariable<AZStd::recursive_mutex>(AZ_FUNCTION_SIGNATURE);
|
||||
}
|
||||
return *s_drillerGlobalMutex;
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,52 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_DRILLER_BUS_H
|
||||
#define AZCORE_DRILLER_BUS_H
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
class mutex;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class DrillerEBusMutex
|
||||
{
|
||||
public:
|
||||
typedef AZStd::recursive_mutex MutexType;
|
||||
|
||||
static MutexType& GetMutex();
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization of the EBusTraits for a driller bus. We make sure
|
||||
* all allocation are made using DebugAllocation (so no engine systems are involved).
|
||||
* In addition we make sure all driller buses use the same Mutex to synchronize data across
|
||||
* threads (so all events came in order all the time), they are still executed in the context of
|
||||
* the thread.
|
||||
*/
|
||||
struct DrillerEBusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
typedef DrillerEBusMutex MutexType;
|
||||
typedef OSStdAllocator AllocatorType;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AZCORE_DRILLER_BUS_H
|
||||
#pragma once
|
||||
@@ -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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_DRILLER_ROOT_HANDLER_H
|
||||
#define AZCORE_DRILLER_ROOT_HANDLER_H
|
||||
|
||||
#include <AzCore/Driller/Stream.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
// Please check DrillerRootHandler class... this is the one for direct use.
|
||||
|
||||
/**
|
||||
* Handler for the <Frame><StartData><Driller></Driller></StartData></Frame> tag.
|
||||
*/
|
||||
class DrillerDrillerdataHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
class ParamHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
virtual void OnData(const DrillerSAXParser::Data& dataNode)
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("Name", 0x5e237e06))
|
||||
{
|
||||
dataNode.Read(m_param->name);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Description", 0x6de44026))
|
||||
{
|
||||
m_param->desc = NULL; // ignored
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Type", 0x8cde5729))
|
||||
{
|
||||
dataNode.Read(m_param->type);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Value", 0x1d775834))
|
||||
{
|
||||
dataNode.Read(m_param->value);
|
||||
}
|
||||
}
|
||||
Driller::Param* m_param;
|
||||
};
|
||||
|
||||
virtual DrillerHandlerParser* OnEnterTag(u32 tagName)
|
||||
{
|
||||
if (tagName == AZ_CRC("Param", 0xa4fa7c89))
|
||||
{
|
||||
m_drillerInfo->params.push_back();
|
||||
m_paramHandler.m_param = &m_drillerInfo->params.back();
|
||||
return &m_paramHandler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual void OnData(const DrillerSAXParser::Data& dataNode)
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("Name", 0x5e237e06))
|
||||
{
|
||||
dataNode.Read(m_drillerInfo->id);
|
||||
}
|
||||
}
|
||||
|
||||
DrillerManager::DrillerInfo* m_drillerInfo;
|
||||
ParamHandler m_paramHandler;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for the <Frame><StartData></StartData></Frame> tag
|
||||
*/
|
||||
class DrillerStartdataHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
virtual DrillerHandlerParser* OnEnterTag(u32 tagName)
|
||||
{
|
||||
if (tagName == AZ_CRC("Driller", 0xa6e1fb73))
|
||||
{
|
||||
m_drillers.push_back();
|
||||
m_drillerDataHandler.m_drillerInfo = &m_drillers.back();
|
||||
return &m_drillerDataHandler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
virtual void OnData(const DrillerSAXParser::Data& dataNode)
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("Platform", 0x3952d0cb))
|
||||
{
|
||||
dataNode.Read(m_platform);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int m_platform;
|
||||
DrillerManager::DrillerListType m_drillers;
|
||||
DrillerDrillerdataHandler m_drillerDataHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for the <Frame></Frame> tag
|
||||
*/
|
||||
template<class DrillerContainer>
|
||||
class FrameHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
FrameHandler()
|
||||
: DrillerHandlerParser(DrillerContainer::s_isWarnOnMissingDrillers)
|
||||
, m_currentFrame(-1) {}
|
||||
|
||||
virtual DrillerHandlerParser* OnEnterTag(u32 tagName) { return m_drillersContainer.FindDrillerHandler(tagName); }
|
||||
virtual void OnData(const DrillerSAXParser::Data& dataNode)
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("FrameNum", 0x85a1a919))
|
||||
{
|
||||
dataNode.Read(m_currentFrame);
|
||||
}
|
||||
}
|
||||
DrillerContainer m_drillersContainer;
|
||||
int m_currentFrame;
|
||||
};
|
||||
|
||||
/**
|
||||
* Use this class a input parameter to DrillerSAXParserHandler::DrillerSAXParserHandler(). It will handle all root level
|
||||
* tags for a standard driller input stream stream.
|
||||
*
|
||||
* DrillerContainer should comply to the following requirements:
|
||||
* - default constructible
|
||||
* - has a static const bool s_isWarnOnMissingDrillers member to indicate if you want to
|
||||
* trigger a warning when a driller is not found in the class.
|
||||
* - implement a function DrillerHandlerParser* DrillerContainer::FindDrillerHandler(u32 drillerName)
|
||||
*
|
||||
*/
|
||||
template<class DrillerContainer>
|
||||
class DrillerRootHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
DrillerContainer* GetDrillerContainer() { return m_frameHandler.m_drillersContainer; }
|
||||
|
||||
virtual DrillerHandlerParser* OnEnterTag(u32 tagName)
|
||||
{
|
||||
if (tagName == AZ_CRC("StartData", 0xecf3f53f))
|
||||
{
|
||||
return &m_drillerSessionInfo;
|
||||
}
|
||||
if (tagName == AZ_CRC("Frame", 0xb5f83ccd))
|
||||
{
|
||||
return &m_frameHandler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
DrillerStartdataHandler m_drillerSessionInfo;
|
||||
FrameHandler<DrillerContainer> m_frameHandler;
|
||||
};
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_DRILLER_ROOT_HANDLER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,893 +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/Driller/Stream.h>
|
||||
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/Math/Obb.h>
|
||||
#include <AzCore/Math/Plane.h>
|
||||
|
||||
#include <AzCore/std/time.h>
|
||||
|
||||
#if !defined(AZCORE_EXCLUDE_ZLIB)
|
||||
# define AZ_FILE_STREAM_COMPRESSION
|
||||
#endif // AZCORE_EXCLUDE_ZLIB
|
||||
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
# include <AzCore/Compression/Compression.h>
|
||||
#endif // AZ_FILE_STREAM_COMPRESSION
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller output stream
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Vector3& v)
|
||||
{
|
||||
float data[4];
|
||||
unsigned int dataSize = 3 * sizeof(float);
|
||||
v.StoreToFloat4(data);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Vector4& v)
|
||||
{
|
||||
float data[4];
|
||||
unsigned int dataSize = 4 * sizeof(float);
|
||||
v.StoreToFloat4(data);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Aabb& aabb)
|
||||
{
|
||||
float data[7];
|
||||
unsigned int dataSize = 6 * sizeof(float);
|
||||
aabb.GetMin().StoreToFloat4(data);
|
||||
aabb.GetMax().StoreToFloat4(&data[3]);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Obb& obb)
|
||||
{
|
||||
float data[10];
|
||||
unsigned int dataSize = 10 * sizeof(float); // position (Vector3), rotation (Quaternion) and halfLengths (Vector3)
|
||||
obb.GetPosition().StoreToFloat3(data);
|
||||
obb.GetRotation().StoreToFloat4(&data[3]);
|
||||
obb.GetHalfLengths().StoreToFloat3(&data[7]);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Transform& tm)
|
||||
{
|
||||
float data[12];
|
||||
unsigned int dataSize = 12 * sizeof(float);
|
||||
const Matrix3x4 matrix3x4 = Matrix3x4::CreateFromTransform(tm);
|
||||
matrix3x4.StoreToRowMajorFloat12(data);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Matrix3x3& tm)
|
||||
{
|
||||
float data[9];
|
||||
unsigned int dataSize = 9 * sizeof(float);
|
||||
tm.StoreToRowMajorFloat9(data);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Matrix4x4& tm)
|
||||
{
|
||||
float data[16];
|
||||
unsigned int dataSize = 16 * sizeof(float);
|
||||
tm.StoreToRowMajorFloat16(data);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Quaternion& tm)
|
||||
{
|
||||
float data[4];
|
||||
unsigned int dataSize = 4 * sizeof(float);
|
||||
tm.StoreToFloat4(data);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
void DrillerOutputStream::Write(u32 name, const AZ::Plane& plane)
|
||||
{
|
||||
Write(name, plane.GetPlaneEquationCoefficients());
|
||||
}
|
||||
void DrillerOutputStream::WriteHeader()
|
||||
{
|
||||
StreamHeader sh; // StreamHeader should be endianess independent.
|
||||
WriteBinary(&sh, sizeof(sh));
|
||||
}
|
||||
|
||||
void DrillerOutputStream::WriteTimeUTC(u32 name)
|
||||
{
|
||||
AZStd::sys_time_t now = AZStd::GetTimeUTCMilliSecond();
|
||||
Write(name, now);
|
||||
}
|
||||
|
||||
void DrillerOutputStream::WriteTimeMicrosecond(u32 name)
|
||||
{
|
||||
AZStd::sys_time_t now = AZStd::GetTimeNowMicroSecond();
|
||||
Write(name, now);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller Input Stream
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool DrillerInputStream::ReadHeader()
|
||||
{
|
||||
DrillerOutputStream::StreamHeader sh; // StreamHeader should be endianess independent.
|
||||
unsigned int numRead = ReadBinary(&sh, sizeof(sh));
|
||||
(void)numRead;
|
||||
AZ_Error("IO", numRead == sizeof(sh), "We should have atleast %d bytes in the stream to read the header!", sizeof(sh));
|
||||
if (numRead != sizeof(sh))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_isEndianSwap = AZ::IsBigEndian(static_cast<AZ::PlatformID>(sh.platform)) != AZ::IsBigEndian(AZ::g_currentPlatform);
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller file stream
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//=========================================================================
|
||||
// DrillerOutputFileStream::DrillerOutputFileStream
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
DrillerOutputFileStream::DrillerOutputFileStream()
|
||||
{
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
m_zlib = azcreate(ZLib, (&AllocatorInstance<OSAllocator>::GetAllocator()), OSAllocator);
|
||||
m_zlib->StartCompressor(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DrillerOutputFileStream::~DrillerOutputFileStream
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
DrillerOutputFileStream::~DrillerOutputFileStream()
|
||||
{
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
azdestroy(m_zlib, OSAllocator);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DrillerOutputFileStream::Open
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
bool DrillerOutputFileStream::Open(const char* fileName, int mode, int platformFlags)
|
||||
{
|
||||
if (IO::SystemFile::Open(fileName, mode, platformFlags))
|
||||
{
|
||||
m_dataBuffer.reserve(100 * 1024);
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
// // Enable optional: encode the file in the same format as the streamer so they are interchangeable
|
||||
// IO::CompressorHeader ch;
|
||||
// ch.SetAZCS();
|
||||
// ch.m_compressorId = IO::CompressorZLib::TypeId();
|
||||
// ch.m_uncompressedSize = 0; // will be updated later
|
||||
// AZStd::endian_swap(ch.m_compressorId);
|
||||
// AZStd::endian_swap(ch.m_uncompressedSize);
|
||||
// IO::SystemFile::Write(&ch,sizeof(ch));
|
||||
// IO::CompressorZLibHeader zlibHdr;
|
||||
// zlibHdr.m_numSeekPoints = 0;
|
||||
// IO::SystemFile::Write(&zlibHdr,sizeof(zlibHdr));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DrillerOutputFileStream::Close
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
void DrillerOutputFileStream::Close()
|
||||
{
|
||||
unsigned int dataSizeInBuffer = static_cast<unsigned int>(m_dataBuffer.size());
|
||||
{
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
unsigned int minCompressBufferSize = m_zlib->GetMinCompressedBufferSize(dataSizeInBuffer);
|
||||
if (m_compressionBuffer.size() < minCompressBufferSize) // grow compression buffer if needed
|
||||
{
|
||||
m_compressionBuffer.clear();
|
||||
m_compressionBuffer.resize(minCompressBufferSize);
|
||||
}
|
||||
unsigned int compressedSize;
|
||||
do
|
||||
{
|
||||
compressedSize = m_zlib->Compress(m_dataBuffer.data(), dataSizeInBuffer, m_compressionBuffer.data(), (unsigned)m_compressionBuffer.size(), ZLib::FT_FINISH);
|
||||
if (compressedSize)
|
||||
{
|
||||
IO::SystemFile::Write(m_compressionBuffer.data(), compressedSize);
|
||||
}
|
||||
} while (compressedSize > 0);
|
||||
m_zlib->ResetCompressor();
|
||||
#else
|
||||
if (dataSizeInBuffer)
|
||||
{
|
||||
IO::SystemFile::Write(m_dataBuffer.data(), m_dataBuffer.size());
|
||||
}
|
||||
#endif
|
||||
m_dataBuffer.clear();
|
||||
}
|
||||
IO::SystemFile::Close();
|
||||
}
|
||||
//=========================================================================
|
||||
// DrillerOutputFileStream::WriteBinary
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
void DrillerOutputFileStream::WriteBinary(const void* data, unsigned int dataSize)
|
||||
{
|
||||
size_t dataSizeInBuffer = m_dataBuffer.size();
|
||||
if (dataSizeInBuffer + dataSize > m_dataBuffer.capacity())
|
||||
{
|
||||
if (dataSizeInBuffer > 0)
|
||||
{
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
// we need to flush the data
|
||||
unsigned int dataToCompress = static_cast<unsigned int>(dataSizeInBuffer);
|
||||
unsigned int minCompressBufferSize = m_zlib->GetMinCompressedBufferSize(dataToCompress);
|
||||
if (m_compressionBuffer.size() < minCompressBufferSize) // grow compression buffer if needed
|
||||
{
|
||||
m_compressionBuffer.clear();
|
||||
m_compressionBuffer.resize(minCompressBufferSize);
|
||||
}
|
||||
while (dataToCompress > 0)
|
||||
{
|
||||
unsigned int compressedSize = m_zlib->Compress(m_dataBuffer.data(), dataToCompress, m_compressionBuffer.data(), (unsigned)m_compressionBuffer.size());
|
||||
if (compressedSize)
|
||||
{
|
||||
IO::SystemFile::Write(m_compressionBuffer.data(), compressedSize);
|
||||
}
|
||||
}
|
||||
#else
|
||||
IO::SystemFile::Write(m_dataBuffer.data(), m_dataBuffer.size());
|
||||
#endif
|
||||
m_dataBuffer.clear();
|
||||
}
|
||||
}
|
||||
m_dataBuffer.insert(m_dataBuffer.end(), reinterpret_cast<const unsigned char*>(data), reinterpret_cast<const unsigned char*>(data) + dataSize);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller file input stream
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//=========================================================================
|
||||
// DrillerInputFileStream::DrillerInputFileStream
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
DrillerInputFileStream::DrillerInputFileStream()
|
||||
{
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
m_zlib = azcreate(ZLib, (&AllocatorInstance<OSAllocator>::GetAllocator()), OSAllocator);
|
||||
m_zlib->StartDecompressor();
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DrillerInputFileStream::DrillerInputFileStream
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
DrillerInputFileStream::~DrillerInputFileStream()
|
||||
{
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
azdestroy(m_zlib, OSAllocator);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DrillerInputFileStream::Open
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
bool DrillerInputFileStream::Open(const char* fileName, int mode, int platformFlags)
|
||||
{
|
||||
if (IO::SystemFile::Open(fileName, mode, platformFlags))
|
||||
{
|
||||
DrillerOutputStream::StreamHeader sh;
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
// TODO: optional encode the file in the same format as the streamer so they are interchangeable
|
||||
#endif
|
||||
// first read the header of the stream file.
|
||||
return ReadHeader();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//=========================================================================
|
||||
// DrillerInputFileStream::ReadBinary
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
unsigned int DrillerInputFileStream::ReadBinary(void* data, unsigned int maxDataSize)
|
||||
{
|
||||
// make sure the compressed buffer if full enough...
|
||||
size_t dataToLoad = maxDataSize * 2;
|
||||
m_compressedData.reserve(dataToLoad);
|
||||
while (m_compressedData.size() < dataToLoad)
|
||||
{
|
||||
unsigned char buffer[10 * 1024];
|
||||
IO::SystemFile::SizeType bytesRead = Read(AZ_ARRAY_SIZE(buffer), buffer);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
m_compressedData.insert(m_compressedData.end(), (unsigned char*)buffer, buffer + bytesRead);
|
||||
}
|
||||
if (bytesRead < AZ_ARRAY_SIZE(buffer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
unsigned int dataSize = maxDataSize;
|
||||
unsigned int bytesProcessed = m_zlib->Decompress(m_compressedData.data(), (unsigned)m_compressedData.size(), data, dataSize);
|
||||
unsigned int readSize = maxDataSize - dataSize; // Zlib::Decompress decrements the dataSize parameter by the amount uncompressed
|
||||
#else
|
||||
unsigned int bytesProcessed = AZStd::GetMin((unsigned int)m_compressedData.size(), maxDataSize);
|
||||
unsigned int readSize = bytesProcessed;
|
||||
memcpy(data, m_compressedData.data(), readSize);
|
||||
#endif
|
||||
m_compressedData.erase(m_compressedData.begin(), m_compressedData.begin() + bytesProcessed);
|
||||
return readSize;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DrillerInputFileStream::Close
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
void DrillerInputFileStream::Close()
|
||||
{
|
||||
#if defined(AZ_FILE_STREAM_COMPRESSION)
|
||||
if (m_zlib)
|
||||
{
|
||||
m_zlib->ResetDecompressor();
|
||||
}
|
||||
#endif // AZ_FILE_STREAM_COMPRESSION
|
||||
AZ::IO::SystemFile::Close();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerSAXParser
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//=========================================================================
|
||||
// DrillerSAXParser
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
DrillerSAXParser::DrillerSAXParser(const TagCallbackType& tcb, const DataCallbackType& dcb)
|
||||
: m_tagCallback(tcb)
|
||||
, m_dataCallback(dcb)
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ProcessStream
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerSAXParser::ProcessStream(DrillerInputStream& stream)
|
||||
{
|
||||
static const int processChunkSize = 15 * 1024;
|
||||
char buffer[processChunkSize];
|
||||
unsigned int dataSize;
|
||||
bool isEndianSwap = stream.IsEndianSwap();
|
||||
while ((dataSize = stream.ReadBinary(buffer, processChunkSize)) > 0)
|
||||
{
|
||||
char* dataStart = buffer;
|
||||
char* dataEnd = dataStart + dataSize;
|
||||
bool dataInBuffer = false;
|
||||
if (!m_buffer.empty())
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), dataStart, dataEnd);
|
||||
dataStart = m_buffer.data();
|
||||
dataEnd = dataStart + m_buffer.size();
|
||||
dataInBuffer = true;
|
||||
}
|
||||
const int entrySize = sizeof(DrillerOutputStream::StreamEntry);
|
||||
while (dataStart != dataEnd)
|
||||
{
|
||||
if ((dataEnd - dataStart) < entrySize) // we need at least one entry to proceed
|
||||
{
|
||||
// not enough data to process, buffer it.
|
||||
if (!dataInBuffer)
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), dataStart, dataEnd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DrillerOutputStream::StreamEntry* se = reinterpret_cast<DrillerOutputStream::StreamEntry*>(dataStart);
|
||||
if (isEndianSwap)
|
||||
{
|
||||
// endian swap
|
||||
AZStd::endian_swap(se->name);
|
||||
AZStd::endian_swap(se->sizeAndFlags);
|
||||
}
|
||||
|
||||
u32 dataType = (se->sizeAndFlags & DrillerOutputStream::StreamEntry::dataInternalMask) >> DrillerOutputStream::StreamEntry::dataInternalShift;
|
||||
u32 value = se->sizeAndFlags & DrillerOutputStream::StreamEntry::dataSizeMask;
|
||||
Data de;
|
||||
de.m_name = se->name;
|
||||
de.m_stringPool = stream.GetStringPool();
|
||||
de.m_isPooledString = false;
|
||||
de.m_isPooledStringCrc32 = false;
|
||||
switch (dataType)
|
||||
{
|
||||
case DrillerOutputStream::StreamEntry::INT_TAG:
|
||||
{
|
||||
bool isStart = (value != 0);
|
||||
m_tagCallback(se->name, isStart);
|
||||
dataStart += entrySize;
|
||||
} break;
|
||||
case DrillerOutputStream::StreamEntry::INT_DATA_U8:
|
||||
{
|
||||
u8 value8 = static_cast<u8>(value);
|
||||
de.m_data = &value8;
|
||||
de.m_dataSize = 1;
|
||||
de.m_isEndianSwap = false;
|
||||
m_dataCallback(de);
|
||||
dataStart += entrySize;
|
||||
} break;
|
||||
case DrillerOutputStream::StreamEntry::INT_DATA_U16:
|
||||
{
|
||||
u16 value16 = static_cast<u16>(value);
|
||||
de.m_data = &value16;
|
||||
de.m_dataSize = 2;
|
||||
de.m_isEndianSwap = false;
|
||||
m_dataCallback(de);
|
||||
dataStart += entrySize;
|
||||
} break;
|
||||
case DrillerOutputStream::StreamEntry::INT_DATA_U29:
|
||||
{
|
||||
de.m_data = &value;
|
||||
de.m_dataSize = 4;
|
||||
de.m_isEndianSwap = false;
|
||||
m_dataCallback(de);
|
||||
dataStart += entrySize;
|
||||
} break;
|
||||
case DrillerOutputStream::StreamEntry::INT_POOLED_STRING:
|
||||
{
|
||||
unsigned int userDataSize = value;
|
||||
if ((userDataSize + entrySize) <= (unsigned)(dataEnd - dataStart))
|
||||
{
|
||||
// Add string to the pool
|
||||
AZ_Assert(de.m_stringPool != nullptr, "We require a string pool to parse this stream");
|
||||
AZ::u32 crc32;
|
||||
const char* stringPtr;
|
||||
dataStart += entrySize;
|
||||
de.m_stringPool->InsertCopy(reinterpret_cast<const char*>(dataStart), userDataSize, crc32, &stringPtr);
|
||||
de.m_dataSize = userDataSize;
|
||||
de.m_isEndianSwap = isEndianSwap;
|
||||
de.m_isPooledString = true;
|
||||
de.m_data = const_cast<void*>(static_cast<const void*>(stringPtr));
|
||||
m_dataCallback(de);
|
||||
dataStart += userDataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we can't process data right now add it to the buffer (if we have not done that already)
|
||||
if (!dataInBuffer)
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), dataStart, dataEnd);
|
||||
}
|
||||
dataEnd = dataStart; // exit the loop
|
||||
}
|
||||
} break;
|
||||
case DrillerOutputStream::StreamEntry::INT_POOLED_STRING_CRC32:
|
||||
{
|
||||
de.m_isPooledStringCrc32 = true;
|
||||
AZ_Assert(value == 4, "The data size for a pooled string crc32 should be 4 bytes!");
|
||||
} // continue to INT_SIZE
|
||||
case DrillerOutputStream::StreamEntry::INT_SIZE:
|
||||
{
|
||||
unsigned int userDataSize = value;
|
||||
if ((userDataSize + entrySize) <= (unsigned)(dataEnd - dataStart)) // do we have all the date we need to process...
|
||||
{
|
||||
dataStart += entrySize;
|
||||
de.m_data = dataStart;
|
||||
de.m_dataSize = userDataSize;
|
||||
de.m_isEndianSwap = isEndianSwap;
|
||||
m_dataCallback(de);
|
||||
dataStart += userDataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we can't process data right now add it to the buffer (if we have not done that already)
|
||||
if (!dataInBuffer)
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), dataStart, dataEnd);
|
||||
}
|
||||
dataEnd = dataStart; // exit the loop
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
AZ_Error("DrillerSAXParser",false,"Encounted unknown symbol (%i) while processing stream (%s). Aborting stream.\n",dataType, stream.GetIdentifier());
|
||||
|
||||
// If we can't process anything, we want to just escape the loop, to avoid spinning infinitely
|
||||
dataEnd = dataStart;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
if (dataInBuffer) // if the data was in the buffer remove the processed data!
|
||||
{
|
||||
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + (dataStart - m_buffer.data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrillerSAXParser::Data::Read(AZ::Vector3& v) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 3, "We are expecting 3 floats for Vector3 element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 3);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
v = Vector3::CreateFromFloat3(data);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Vector4& v) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 4, "We are expecting 4 floats for Vector4 element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 4);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
v = Vector4::CreateFromFloat4(data);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Aabb& aabb) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 6, "We are expecting 6 floats for Aabb element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 6);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
Vector3 min = Vector3::CreateFromFloat3(data);
|
||||
Vector3 max = Vector3::CreateFromFloat3(&data[3]);
|
||||
aabb = Aabb::CreateFromMinMax(min, max);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Obb& obb) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 10, "We are expecting 10 floats for Obb element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 10);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
Vector3 position = Vector3::CreateFromFloat3(data);
|
||||
Quaternion rotation = Quaternion::CreateFromFloat4(&data[3]);
|
||||
Vector3 halfLengths = Vector3::CreateFromFloat3(&data[7]);
|
||||
obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Transform& tm) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 12, "We are expecting 12 floats for Transform element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 12);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
const Matrix3x4 matrix3x4 = Matrix3x4::CreateFromRowMajorFloat12(data);
|
||||
tm = Transform::CreateFromMatrix3x4(matrix3x4);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Matrix3x3& tm) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 9, "We are expecting 9 floats for Matrix3x3 element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 9);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
tm = Matrix3x3::CreateFromRowMajorFloat9(data);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Matrix4x4& tm) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 16, "We are expecting 16 floats for Matrix4x4 element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 16);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
tm = Matrix4x4::CreateFromRowMajorFloat16(data);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Quaternion& tm) const
|
||||
{
|
||||
AZ_Assert(m_dataSize == sizeof(float) * 4, "We are expecting 4 floats for Quaternion element 0x%08x with size %d bytes", m_name, m_dataSize);
|
||||
float* data = reinterpret_cast<float*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(data, data + 4);
|
||||
m_isEndianSwap = false;
|
||||
}
|
||||
tm = Quaternion::CreateFromFloat4(data);
|
||||
}
|
||||
void DrillerSAXParser::Data::Read(AZ::Plane& plane) const
|
||||
{
|
||||
AZ::Vector4 coeff;
|
||||
Read(coeff);
|
||||
plane = Plane::CreateFromCoefficients(coeff.GetX(), coeff.GetY(), coeff.GetZ(), coeff.GetW());
|
||||
}
|
||||
|
||||
const char* DrillerSAXParser::Data::PrepareString(unsigned int& stringLength) const
|
||||
{
|
||||
const char* srcData = reinterpret_cast<const char*>(m_data);
|
||||
stringLength = m_dataSize;
|
||||
if (m_stringPool)
|
||||
{
|
||||
AZ::u32 crc32;
|
||||
const char* stringPtr;
|
||||
if (m_isPooledStringCrc32)
|
||||
{
|
||||
crc32 = *reinterpret_cast<AZ::u32*>(m_data);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(crc32);
|
||||
}
|
||||
stringPtr = m_stringPool->Find(crc32);
|
||||
AZ_Assert(stringPtr != nullptr, "Failed to find string with id 0x%08x in the string pool, proper stream read is impossible!", crc32);
|
||||
stringLength = static_cast<unsigned int>(strlen(stringPtr));
|
||||
}
|
||||
else if (m_isPooledString)
|
||||
{
|
||||
stringPtr = srcData; // already stored in the pool just transfer the pointer
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store copy of the string in the pool to save memory (keep only one reference of the string).
|
||||
m_stringPool->InsertCopy(reinterpret_cast<const char*>(srcData), stringLength, crc32, &stringPtr);
|
||||
}
|
||||
srcData = stringPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(m_isPooledString == false && m_isPooledStringCrc32 == false, "This stream requires using of a string pool as the string is send only once and afterwards only the Crc32 is used!");
|
||||
}
|
||||
return srcData;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerDOMParser
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//=========================================================================
|
||||
// Node::GetTag
|
||||
// [1/23/2013]
|
||||
//=========================================================================
|
||||
const DrillerDOMParser::Node* DrillerDOMParser::Node::GetTag(u32 tagName) const
|
||||
{
|
||||
const Node* tagNode = nullptr;
|
||||
for (Node::NodeListType::const_iterator i = m_tags.begin(); i != m_tags.end(); ++i)
|
||||
{
|
||||
if ((*i).m_name == tagName)
|
||||
{
|
||||
tagNode = &*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tagNode;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Node::GetData
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
const DrillerDOMParser::Data* DrillerDOMParser::Node::GetData(u32 dataName) const
|
||||
{
|
||||
const Data* dataNode = nullptr;
|
||||
for (Node::DataListType::const_iterator i = m_data.begin(); i != m_data.end(); ++i)
|
||||
{
|
||||
if (i->m_name == dataName)
|
||||
{
|
||||
dataNode = &*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dataNode;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DrillerDOMParser
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
DrillerDOMParser::DrillerDOMParser(bool isPersistentInputData)
|
||||
: DrillerSAXParser(TagCallbackType(this, &DrillerDOMParser::OnTag), DataCallbackType(this, &DrillerDOMParser::OnData))
|
||||
, m_isPersistentInputData(isPersistentInputData)
|
||||
{
|
||||
m_root.m_name = 0;
|
||||
m_root.m_parent = nullptr;
|
||||
m_topNode = &m_root;
|
||||
}
|
||||
static int g_numFree = 0;
|
||||
//=========================================================================
|
||||
// ~DrillerDOMParser
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
DrillerDOMParser::~DrillerDOMParser()
|
||||
{
|
||||
DeleteNode(m_root);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnTag
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerDOMParser::OnTag(AZ::u32 name, bool isOpen)
|
||||
{
|
||||
if (isOpen)
|
||||
{
|
||||
m_topNode->m_tags.push_back();
|
||||
Node& node = m_topNode->m_tags.back();
|
||||
node.m_name = name;
|
||||
node.m_parent = m_topNode;
|
||||
|
||||
m_topNode = &node;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(m_topNode->m_name == name, "We have opened tag with name 0x%08x and closing with name 0x%08x", m_topNode->m_name, name);
|
||||
m_topNode = m_topNode->m_parent;
|
||||
}
|
||||
}
|
||||
//=========================================================================
|
||||
// OnData
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerDOMParser::OnData(const Data& data)
|
||||
{
|
||||
Data de = data;
|
||||
if (!m_isPersistentInputData)
|
||||
{
|
||||
de.m_data = azmalloc(data.m_dataSize, 1, OSAllocator);
|
||||
memcpy(const_cast<void*>(de.m_data), data.m_data, data.m_dataSize);
|
||||
}
|
||||
m_topNode->m_data.push_back(de);
|
||||
}
|
||||
//=========================================================================
|
||||
// DeleteNode
|
||||
// [3/23/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
DrillerDOMParser::DeleteNode(Node& node)
|
||||
{
|
||||
if (!m_isPersistentInputData)
|
||||
{
|
||||
for (Node::DataListType::iterator iter = node.m_data.begin(); iter != node.m_data.end(); ++iter)
|
||||
{
|
||||
azfree(iter->m_data, OSAllocator, iter->m_dataSize);
|
||||
++g_numFree;
|
||||
}
|
||||
node.m_data.clear();
|
||||
}
|
||||
for (Node::NodeListType::iterator iter = node.m_tags.begin(); iter != node.m_tags.end(); ++iter)
|
||||
{
|
||||
DeleteNode(*iter);
|
||||
}
|
||||
node.m_tags.clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerSAXParserHandler
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//=========================================================================
|
||||
// DrillerSAXParserHandler
|
||||
// [3/14/2013]
|
||||
//=========================================================================
|
||||
DrillerSAXParserHandler::DrillerSAXParserHandler(DrillerHandlerParser* rootHandler)
|
||||
: DrillerSAXParser(TagCallbackType(this, &DrillerSAXParserHandler::OnTag), DataCallbackType(this, &DrillerSAXParserHandler::OnData))
|
||||
{
|
||||
// Push the root element
|
||||
m_stack.push_back(rootHandler);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnTag
|
||||
// [3/14/2013]
|
||||
//=========================================================================
|
||||
void DrillerSAXParserHandler::OnTag(u32 name, bool isOpen)
|
||||
{
|
||||
if (m_stack.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* childHandler = nullptr;
|
||||
DrillerHandlerParser* currentHandler = m_stack.back();
|
||||
if (isOpen)
|
||||
{
|
||||
if (currentHandler != nullptr)
|
||||
{
|
||||
childHandler = currentHandler->OnEnterTag(name);
|
||||
AZ_Warning("Driller", !currentHandler->IsWarnOnUnsupportedTags() || childHandler != nullptr, "Could not find handler for tag 0x%08x", name);
|
||||
}
|
||||
m_stack.push_back(childHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stack.pop_back();
|
||||
if (!m_stack.empty())
|
||||
{
|
||||
DrillerHandlerParser* parentHandler = m_stack.back();
|
||||
if (parentHandler)
|
||||
{
|
||||
parentHandler->OnExitTag(currentHandler, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnData
|
||||
// [3/14/2013]
|
||||
//=========================================================================
|
||||
void DrillerSAXParserHandler::OnData(const DrillerSAXParser::Data& data)
|
||||
{
|
||||
if (m_stack.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* currentHandler = m_stack.back();
|
||||
if (currentHandler)
|
||||
{
|
||||
currentHandler->OnData(data);
|
||||
}
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,848 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_DRILLER_STREAM_H
|
||||
#define AZCORE_DRILLER_STREAM_H
|
||||
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
|
||||
#include <AzCore/std/delegate/delegate.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/forward_list.h>
|
||||
#include <AzCore/std/typetraits/is_signed.h>
|
||||
#include <AzCore/std/typetraits/is_pod.h>
|
||||
|
||||
#include <AzCore/IO/SystemFile.h> // for the Driller direct file stream
|
||||
#include <AzCore/PlatformId/PlatformId.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class Vector3;
|
||||
class Vector4;
|
||||
class Aabb;
|
||||
class Obb;
|
||||
class Transform;
|
||||
class Matrix3x3;
|
||||
class Matrix4x4;
|
||||
class Quaternion;
|
||||
class Plane;
|
||||
class ZLib;
|
||||
|
||||
namespace IO
|
||||
{
|
||||
class Stream;
|
||||
}
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
template<class T>
|
||||
struct vector
|
||||
{
|
||||
typedef AZStd::vector<T, OSStdAllocator> type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct forward_list
|
||||
{
|
||||
typedef AZStd::forward_list<T, OSStdAllocator> type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for a string pool which can be used by input/output streams to avoid storing multiple copies of the same
|
||||
* string in the stream. Of course this comes at the bookkeeping cost of the table.
|
||||
*/
|
||||
class DrillerStringPool
|
||||
{
|
||||
public:
|
||||
virtual ~DrillerStringPool() {}
|
||||
|
||||
/**
|
||||
* Add a copy of the string to the pool. If we return true the string was added otherwise it was already in the bool.
|
||||
* In both cases the crc32 of the string and the pointer to the shared copy is returned (optional for poolStringAddress)!
|
||||
*/
|
||||
virtual bool InsertCopy(const char* string, unsigned int length, AZ::u32& crc32, const char** poolStringAddress = NULL) = 0;
|
||||
|
||||
/**
|
||||
* Same as the InsertCopy above without actually coping the string into the pool. The pool assumes that
|
||||
* none of the strings added to the pool will be deleted.
|
||||
*/
|
||||
virtual bool Insert(const char* string, unsigned int length, AZ::u32& crc32) = 0;
|
||||
|
||||
/// Finds a string in the pool by crc32.
|
||||
virtual const char* Find(AZ::u32 crc32) = 0;
|
||||
|
||||
virtual void Erase(AZ::u32 crc32) = 0;
|
||||
|
||||
/// Clears all the strings in the pool, make sure you don't reference any strings before you call that function.
|
||||
virtual void Reset() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class DrillerOutputStream
|
||||
{
|
||||
protected:
|
||||
friend class DrillerManagerImpl;
|
||||
friend class DrillerSAXParser;
|
||||
struct StreamEntry
|
||||
{
|
||||
enum InternalDataSize // max 8 values as we use 3 bit to store them
|
||||
{
|
||||
INT_SIZE = 0, ///< No internal data, we store the data size. IMPORTANT: INT_SIZE should be 0 the code makes assumptions based on that
|
||||
INT_TAG, ///< True if this entry is tag
|
||||
INT_DATA_U8, ///< Internal data u8 stored (1 byte)
|
||||
INT_DATA_U16, ///< Internal data u16 stored (2 bytes)
|
||||
INT_DATA_U29, ///< Internal data u32 stored (4 bytes) for which we use only the first 29 bits.
|
||||
INT_POOLED_STRING_CRC32, ///< Data size should be 4 bytes crc32 that a string CRC and it require string pool.
|
||||
INT_POOLED_STRING, ///< This data contains a string which should be inserted in the string pool.
|
||||
};
|
||||
static const u32 dataSizeMask = 0x1fffffff;
|
||||
static const u32 dataInternalMask = 0xE0000000;
|
||||
static const u32 dataInternalShift = 29;
|
||||
|
||||
u32 name; ///< data or tag name
|
||||
u32 sizeAndFlags; ///<
|
||||
};
|
||||
|
||||
template<class T, size_t Size, bool isIntegralType>
|
||||
struct IntergralType;
|
||||
|
||||
template<class T>
|
||||
struct IntergralType<T, 1, true>
|
||||
{
|
||||
static void Write(DrillerOutputStream& stream, u32 name, const T& data)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_DATA_U8) << StreamEntry::dataInternalShift;
|
||||
de.sizeAndFlags |= *reinterpret_cast<const u8*>(&data);
|
||||
stream.WriteBinary(de);
|
||||
}
|
||||
};
|
||||
template<class T>
|
||||
struct IntergralType<T, 2, true>
|
||||
{
|
||||
static void Write(DrillerOutputStream& stream, u32 name, const T& data)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_DATA_U16) << StreamEntry::dataInternalShift;
|
||||
de.sizeAndFlags |= *reinterpret_cast<const u16*>(&data);
|
||||
stream.WriteBinary(de);
|
||||
}
|
||||
};
|
||||
template<class T>
|
||||
struct IntergralType<T, 4, true>
|
||||
{
|
||||
static void Write(DrillerOutputStream& stream, u32 name, const T& data)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
const u32* uintData = reinterpret_cast<const u32*>(&data);
|
||||
if (((*uintData) & StreamEntry::dataSizeMask) == *uintData) // check if we can store it internally
|
||||
{
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_DATA_U29) << StreamEntry::dataInternalShift;
|
||||
de.sizeAndFlags |= *uintData;
|
||||
stream.WriteBinary(de);
|
||||
}
|
||||
else
|
||||
{
|
||||
de.sizeAndFlags = 4;
|
||||
stream.WriteBinary(de);
|
||||
stream.WriteBinary(&data, de.sizeAndFlags);
|
||||
}
|
||||
}
|
||||
};
|
||||
template<class T>
|
||||
struct IntergralType<T, 8, true>
|
||||
{
|
||||
static void Write(DrillerOutputStream& stream, u32 name, const T& data)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
const u64* uintData = reinterpret_cast<const u64*>(&data);
|
||||
if (((*uintData) & static_cast<u64>(StreamEntry::dataSizeMask)) == *uintData) // check if we can store it internally
|
||||
{
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_DATA_U29) << StreamEntry::dataInternalShift;
|
||||
de.sizeAndFlags |= static_cast<u32>(*uintData);
|
||||
stream.WriteBinary(de);
|
||||
}
|
||||
else
|
||||
{
|
||||
de.sizeAndFlags = 8;
|
||||
stream.WriteBinary(de);
|
||||
stream.WriteBinary(&data, de.sizeAndFlags);
|
||||
}
|
||||
}
|
||||
};
|
||||
template<class T>
|
||||
struct IntergralType<T*, sizeof(void*), false>
|
||||
{
|
||||
static void Write(DrillerOutputStream& stream, u32 name, const T* pointer)
|
||||
{
|
||||
size_t id = reinterpret_cast<size_t>(pointer);
|
||||
IntergralType<size_t, sizeof(id), true>::Write(stream, name, id);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* Each stream with start with this header, before anything else.
|
||||
*/
|
||||
struct StreamHeader
|
||||
{
|
||||
StreamHeader()
|
||||
: platform((u8)g_currentPlatform) {}
|
||||
u8 platform;
|
||||
};
|
||||
|
||||
DrillerOutputStream(DrillerStringPool* stringPool = NULL)
|
||||
: m_stringPool(stringPool) { }
|
||||
virtual ~DrillerOutputStream() {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Write
|
||||
inline void BeginTag(u32 name)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_TAG) << StreamEntry::dataInternalShift;
|
||||
de.sizeAndFlags |= 1; // true - open tag
|
||||
WriteBinary(de);
|
||||
}
|
||||
inline void EndTag(u32 name)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_TAG) << StreamEntry::dataInternalShift;
|
||||
WriteBinary(de);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Generic
|
||||
template<class T>
|
||||
inline void Write(u32 name, const T& data)
|
||||
{
|
||||
// User should handle non specialized non integral types.
|
||||
IntergralType<T, sizeof(T), AZStd::is_integral<T>::value || AZStd::is_enum<T>::value>::Write(*this, name, data);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Binary and strings
|
||||
inline void Write(u32 name, const void* data, unsigned int dataSize)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
WriteBinary(de);
|
||||
WriteBinary(data, dataSize);
|
||||
}
|
||||
inline void Write(u32 name, const char* string, bool isCopyString = true)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = static_cast<unsigned int>(strlen(string));
|
||||
AZ_Assert(de.sizeAndFlags <= StreamEntry::dataSizeMask, "Invalid string length! String is too long, length is limited to %u bytes!", StreamEntry::dataSizeMask);
|
||||
;
|
||||
if (m_stringPool)
|
||||
{
|
||||
AZ::u32 crc;
|
||||
bool isInserted = isCopyString ? m_stringPool->InsertCopy(string, de.sizeAndFlags, crc) : m_stringPool->Insert(string, de.sizeAndFlags, crc);
|
||||
if (!isInserted) // if already inserted, it means it's in the stream, so store the crc only.
|
||||
{
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_POOLED_STRING_CRC32) << StreamEntry::dataInternalShift;
|
||||
de.sizeAndFlags |= sizeof(crc);
|
||||
WriteBinary(de);
|
||||
WriteBinary(&crc, sizeof(crc));
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::u32 stringSize = de.sizeAndFlags;
|
||||
de.sizeAndFlags |= (u32)(StreamEntry::INT_POOLED_STRING) << StreamEntry::dataInternalShift;
|
||||
WriteBinary(de);
|
||||
WriteBinary(string, stringSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBinary(de);
|
||||
WriteBinary(string, de.sizeAndFlags);
|
||||
}
|
||||
}
|
||||
template<class Allocator>
|
||||
inline void Write(u32 name, const AZStd::basic_string<AZStd::string::value_type, AZStd::string::traits_type, Allocator>& str, bool isCopyString = true)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = static_cast<AZ::u32>(str.size());
|
||||
AZ_Assert(de.sizeAndFlags <= StreamEntry::dataSizeMask, "Invalid string length! String is too long, length is limited to %u bytes!", StreamEntry::dataSizeMask);
|
||||
if (m_stringPool)
|
||||
{
|
||||
AZ::u32 crc;
|
||||
bool isInserted = isCopyString ? m_stringPool->InsertCopy(str.c_str(), de.sizeAndFlags, crc) : m_stringPool->Insert(str.c_str(), de.sizeAndFlags, crc);
|
||||
if (!isInserted) // if already inserted, it means it's in the stream, so store the crc only.
|
||||
{
|
||||
de.sizeAndFlags = (u32)(StreamEntry::INT_POOLED_STRING_CRC32) << StreamEntry::dataInternalShift;
|
||||
de.sizeAndFlags |= sizeof(crc);
|
||||
WriteBinary(de);
|
||||
WriteBinary(&crc, sizeof(crc));
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::u32 stringSize = de.sizeAndFlags;
|
||||
de.sizeAndFlags |= (u32)(StreamEntry::INT_POOLED_STRING) << StreamEntry::dataInternalShift;
|
||||
WriteBinary(de);
|
||||
WriteBinary(str.data(), stringSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBinary(de);
|
||||
WriteBinary(str.data(), de.sizeAndFlags);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline void Write(u32 name, const AZStd::basic_string<AZStd::wstring::value_type, AZStd::wstring::traits_type, Allocator>& str)
|
||||
{
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = static_cast<AZ::u32>(str.size());
|
||||
AZ_Assert(de.sizeAndFlags <= StreamEntry::dataSizeMask, "Invalid string length! String is too long, length is limited to %u bytes!", StreamEntry::dataSizeMask);
|
||||
WriteBinary(de);
|
||||
WriteBinary(str.data(), de.sizeAndFlags * sizeof(AZStd::wstring::value_type));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// math types
|
||||
inline void Write(u32 name, float f)
|
||||
{
|
||||
Write(name, &f, static_cast<unsigned int>(sizeof(float)));
|
||||
}
|
||||
inline void Write(u32 name, double d)
|
||||
{
|
||||
Write(name, &d, static_cast<unsigned int>(sizeof(double)));
|
||||
}
|
||||
|
||||
void Write(u32 name, const AZ::Vector3& v);
|
||||
void Write(u32 name, const AZ::Vector4& v);
|
||||
void Write(u32 name, const AZ::Aabb& aabb);
|
||||
void Write(u32 name, const AZ::Obb& obb);
|
||||
void Write(u32 name, const AZ::Transform& tm);
|
||||
void Write(u32 name, const AZ::Matrix3x3& tm);
|
||||
void Write(u32 name, const AZ::Matrix4x4& tm);
|
||||
void Write(u32 name, const AZ::Quaternion& tm);
|
||||
void Write(u32 name, const AZ::Plane& plane);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// containers
|
||||
template<class InputIterator>
|
||||
inline void Write(u32 name, InputIterator first, InputIterator last)
|
||||
{
|
||||
// we can specialize for contiguous_iterator_tag so have only 1 write for all elements
|
||||
size_t numElements = AZStd::distance(first, last);
|
||||
size_t elementSize = sizeof(typename AZStd::iterator_traits<InputIterator>::value_type);
|
||||
unsigned int dataSize = static_cast<unsigned int>(numElements * elementSize);
|
||||
StreamEntry de;
|
||||
de.name = name;
|
||||
de.sizeAndFlags = dataSize;
|
||||
AZ_Assert(dataSize < StreamEntry::dataSizeMask, "Invalid data size, size is limited to %d bytes!", StreamEntry::dataSizeMask - 1);
|
||||
WriteBinary(de);
|
||||
//WriteBinary(data,dataSize); for contiguous_iterator_tag
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
WriteBinary(&*first, static_cast<unsigned int>(elementSize));
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Raw data to the output
|
||||
template<class T>
|
||||
inline void WriteBinary(const T& data)
|
||||
{
|
||||
WriteBinary(&data, sizeof(T));
|
||||
}
|
||||
|
||||
virtual void WriteBinary(const void* data, unsigned int dataSize) = 0;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Write a time stamp (AZStd::sys_time_t) in millisecond since 1970/01/01 00:00:00 UTC.
|
||||
* On older windows this function can have ~15 ms resolution, in such cases use \ref GetTimeNowMicroSecond
|
||||
*/
|
||||
void WriteTimeUTC(u32 name);
|
||||
|
||||
/**
|
||||
* Write a time stamp (AZStd::sys_time_t) in micriseconds. This function is inaccurate for long periods but it has ms resolution.
|
||||
* For long periods use \ref WriteTimeUTC.
|
||||
*/
|
||||
void WriteTimeMicrosecond(u32 name);
|
||||
|
||||
/// Called when the driller is moving on the next frame, so you can flush you current buffer to network/disk.
|
||||
virtual void OnEndOfFrame() {}
|
||||
|
||||
/// Sets the string pool used for this stream. To disable the pool just set it to NULL.
|
||||
void SetStringPool(DrillerStringPool* stringPool) { m_stringPool = stringPool; }
|
||||
|
||||
protected:
|
||||
/// Write the Stream header structure (should be endianess independent).
|
||||
void WriteHeader();
|
||||
|
||||
DrillerStringPool* m_stringPool; ///< Optional pointer to a string pool.
|
||||
};
|
||||
|
||||
/**
|
||||
* For efficiency all data read functions are placed with the parsers.
|
||||
*/
|
||||
class DrillerInputStream
|
||||
{
|
||||
public:
|
||||
DrillerInputStream(DrillerStringPool* stringPool = NULL)
|
||||
: m_isEndianSwap(false)
|
||||
, m_stringPool(stringPool) {}
|
||||
virtual ~DrillerInputStream() {}
|
||||
|
||||
bool IsEndianSwap() const { return m_isEndianSwap; }
|
||||
/// Reads binary data from a stream to to maxDataSize. Returns 0 if no more data.
|
||||
virtual unsigned int ReadBinary(void* data, unsigned int maxDataSize) = 0;
|
||||
|
||||
/// Sets the string pool used for this stream. To disable the pool just set it to NULL.
|
||||
void SetStringPool(DrillerStringPool* stringPool) { m_stringPool = stringPool; }
|
||||
DrillerStringPool* GetStringPool() const { return m_stringPool; }
|
||||
|
||||
void SetIdentifier(const char* identifier) { m_streamIdentifier = identifier; }
|
||||
const char* GetIdentifier() const { return m_streamIdentifier.c_str(); }
|
||||
|
||||
protected:
|
||||
/// Read the Stream header structure
|
||||
bool ReadHeader();
|
||||
|
||||
bool m_isEndianSwap;
|
||||
DrillerStringPool* m_stringPool; ///< Optional pointer to a string pool.
|
||||
AZStd::string m_streamIdentifier;
|
||||
};
|
||||
|
||||
/**
|
||||
* Outputs all stream data into a memory buffer. It will grow automatically.
|
||||
*/
|
||||
class DrillerOutputMemoryStream
|
||||
: public DrillerOutputStream
|
||||
{
|
||||
protected:
|
||||
vector<unsigned char>::type m_data;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerOutputMemoryStream, OSAllocator, 0)
|
||||
DrillerOutputMemoryStream(size_t memorySize = 2048) { m_data.reserve(memorySize); }
|
||||
const unsigned char* GetData() const { return m_data.data(); }
|
||||
unsigned int GetDataSize() const { return static_cast<unsigned int>(m_data.size()); }
|
||||
inline void Reset() { m_data.clear(); }
|
||||
void WriteBinary(const void* data, unsigned int dataSize) override
|
||||
{
|
||||
m_data.insert(m_data.end(), reinterpret_cast<const unsigned char*>(data), reinterpret_cast<const unsigned char*>(data) + dataSize);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Reads data from a memory stream. Data is NOT copied and must be persistent while we are using it.
|
||||
*/
|
||||
class DrillerInputMemoryStream
|
||||
: public DrillerInputStream
|
||||
{
|
||||
const unsigned char* m_data;
|
||||
const unsigned char* m_dataEnd;
|
||||
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerInputMemoryStream, OSAllocator, 0)
|
||||
DrillerInputMemoryStream(const char* streamIdentifier = "", const void* data = nullptr, unsigned int dataSize = 0)
|
||||
: DrillerInputStream()
|
||||
, m_data(nullptr)
|
||||
, m_dataEnd(nullptr)
|
||||
{
|
||||
if (data != nullptr)
|
||||
{
|
||||
SetData(streamIdentifier, data, dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(const char* streamIdentifier, const void* data, unsigned int dataSize)
|
||||
{
|
||||
SetIdentifier(streamIdentifier);
|
||||
|
||||
AZ_Assert(data != nullptr && dataSize > 0, "We must have a valid pointer %p and data size %d !", data, dataSize);
|
||||
if (m_data == nullptr) // this is the first data chuck, read the platform
|
||||
{
|
||||
m_data = reinterpret_cast<const unsigned char*>(data);
|
||||
m_dataEnd = m_data + dataSize;
|
||||
ReadHeader();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data = reinterpret_cast<const unsigned char*>(data);
|
||||
m_dataEnd = m_data + dataSize;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int GetDataLeft() const { return static_cast<unsigned int>(m_dataEnd - m_data); }
|
||||
unsigned int ReadBinary(void* data, unsigned int maxDataSize) override
|
||||
{
|
||||
AZ_Assert(m_data != nullptr, "You must call SetData function, before you can read data!");
|
||||
AZ_Assert(data != nullptr && maxDataSize > 0, "We must have a valid pointer and max data size!");
|
||||
unsigned int dataToCopy = AZStd::GetMin(static_cast<unsigned int>(m_dataEnd - m_data), maxDataSize);
|
||||
if (dataToCopy)
|
||||
{
|
||||
memcpy(data, m_data, dataToCopy);
|
||||
}
|
||||
m_data += dataToCopy;
|
||||
return dataToCopy;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Outputs driller data to a file (buffered)
|
||||
* IMPORTANT: We provide direct IO classes (instead trough Streamer), because the driller
|
||||
* framework should NOT use engine systems (for example imagine we are drilling the Streamer, using it to
|
||||
* write the drilled data will invalidate all the results as the streamer is unaware which data is driller data and which not)
|
||||
*/
|
||||
class DrillerOutputFileStream
|
||||
: public IO::SystemFile
|
||||
, public DrillerOutputStream
|
||||
{
|
||||
ZLib* m_zlib;
|
||||
vector<unsigned char>::type m_compressionBuffer;
|
||||
vector<unsigned char>::type m_dataBuffer;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerOutputFileStream, OSAllocator, 0)
|
||||
DrillerOutputFileStream();
|
||||
~DrillerOutputFileStream();
|
||||
bool Open(const char* fileName, int mode, int platformFlags = 0);
|
||||
void Close();
|
||||
|
||||
void WriteBinary(const void* data, unsigned int dataSize) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads driller data from a file.
|
||||
*/
|
||||
class DrillerInputFileStream
|
||||
: public AZ::IO::SystemFile
|
||||
, public DrillerInputStream
|
||||
{
|
||||
ZLib* m_zlib;
|
||||
vector<unsigned char>::type m_compressedData;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerInputFileStream, OSAllocator, 0)
|
||||
DrillerInputFileStream();
|
||||
~DrillerInputFileStream();
|
||||
bool Open(const char* fileName, int mode, int platformFlags = 0);
|
||||
unsigned int ReadBinary(void* data, unsigned int maxDataSize) override;
|
||||
void Close();
|
||||
};
|
||||
|
||||
/**
|
||||
* SAX like stream parser for driller data. We can stream the data
|
||||
* and we will trigger events as tags and data (attributes) arrive. We use less memory this way.
|
||||
* \note SAX is used as reference name, we are NOT trying to compatible with
|
||||
* any specs. (not that SAX has specs)
|
||||
* IMPORTANT: All data callbacks (tag and data) are called in the order they were at store. You can
|
||||
* use this order as event index.
|
||||
*/
|
||||
class DrillerSAXParser
|
||||
{
|
||||
public:
|
||||
struct Data
|
||||
{
|
||||
u32 m_name; ///< Crc name of the data entry.
|
||||
void* m_data; ///< Pointer to copy if the loaded data.
|
||||
unsigned int m_dataSize; ///< Data size in bytes.
|
||||
mutable bool m_isEndianSwap; ///< True if the user will need to swap the endian when he access the data. We swap the data is the storage so we can read it multiple times without swap.
|
||||
DrillerStringPool* m_stringPool; ///< Pointer to optional data string pool.
|
||||
bool m_isPooledString; ///< True if we have a pooled string (stored in the stringPool already).
|
||||
bool m_isPooledStringCrc32; ///< True is we have stored a crc32 (4 bytes) which refers to a string from the String Pool.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Generic
|
||||
template<class T>
|
||||
inline void Read(T& t) const
|
||||
{
|
||||
static_assert(AZStd::is_pod<T>::value, "T must be plain-old-data");
|
||||
|
||||
AZ_Assert(sizeof(t) >= m_dataSize, "You are about to lose some data, this is wrong.");
|
||||
if (m_dataSize == sizeof(t))
|
||||
{
|
||||
// do a memcpy as alignment might be required for some data types! This is not performance critical as we usually load drill files on x86/x64
|
||||
// which doesn't care about alignment.
|
||||
memcpy(&t, m_data, m_dataSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(AZStd::is_pointer<T>::value || AZStd::is_integral<T>::value, "We support extending only for integral types, float and pointers up to 8 bytes!");
|
||||
|
||||
if (AZStd::is_signed<T>::value)
|
||||
{
|
||||
switch (m_dataSize)
|
||||
{
|
||||
case 1:
|
||||
t = static_cast<T>(*reinterpret_cast<s8*>(m_data));
|
||||
break;
|
||||
case 2:
|
||||
t = static_cast<T>(*reinterpret_cast<s16*>(m_data));
|
||||
break;
|
||||
case 4:
|
||||
t = static_cast<T>(*reinterpret_cast<s32*>(m_data));
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Source data size unsupported... we can extend only 1,2,4 bytes into 2,4,8 bytes integrals");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_dataSize)
|
||||
{
|
||||
case 1:
|
||||
t = static_cast<T>(*reinterpret_cast<u8*>(m_data));
|
||||
break;
|
||||
case 2:
|
||||
t = static_cast<T>(*reinterpret_cast<u16*>(m_data));
|
||||
break;
|
||||
case 4:
|
||||
t = static_cast<T>(*reinterpret_cast<u32*>(m_data));
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Source data size unsupported... we can extend only 1,2,4 bytes into 2,4,8 bytes integrals");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(t);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Read(bool& b) const
|
||||
{
|
||||
u8* data = reinterpret_cast<u8*>(m_data);
|
||||
b = false;
|
||||
for (unsigned int i = 0; i < m_dataSize; ++i)
|
||||
{
|
||||
if (data[i] != 0)
|
||||
{
|
||||
b = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Binary and strings
|
||||
inline unsigned int Read(void* buffer, unsigned int bufferSize) const
|
||||
{
|
||||
unsigned int dataToCopy = AZStd::GetMin(m_dataSize, bufferSize);
|
||||
memcpy(buffer, m_data, dataToCopy);
|
||||
// no data swap
|
||||
return dataToCopy;
|
||||
}
|
||||
// a call avilable only when we use a string pool, it will return the pointer of string in the pool, so you don't need to copy it or do any fancy procedures.
|
||||
inline const char* ReadPooledString() const
|
||||
{
|
||||
AZ_Assert(m_stringPool != nullptr, "This read type is supported only when we use string pool!");
|
||||
unsigned int srcDataSize;
|
||||
return PrepareString(srcDataSize);
|
||||
}
|
||||
inline unsigned int Read(char* string, unsigned int maxNumChars) const
|
||||
{
|
||||
unsigned int srcDataSize;
|
||||
const char* srcData = PrepareString(srcDataSize);
|
||||
unsigned int dataToCopy = AZStd::GetMin(maxNumChars - 1, srcDataSize);
|
||||
memcpy(string, srcData, dataToCopy);
|
||||
string[dataToCopy] = '\0';
|
||||
return dataToCopy;
|
||||
}
|
||||
template<class Allocator>
|
||||
inline unsigned int Read(AZStd::basic_string<AZStd::string::value_type, AZStd::string::traits_type, Allocator>& str) const
|
||||
{
|
||||
unsigned int srcDataSize;
|
||||
const char* srcData = PrepareString(srcDataSize);
|
||||
str = AZStd::basic_string<AZStd::string::value_type, AZStd::string::traits_type, Allocator>(static_cast<const AZStd::string::value_type*>(srcData), srcDataSize);
|
||||
return m_dataSize;
|
||||
}
|
||||
template<class Allocator>
|
||||
inline unsigned int Read(AZStd::basic_string<AZStd::wstring::value_type, AZStd::wstring::traits_type, Allocator>& str) const
|
||||
{
|
||||
// wstring pooling not supported yet
|
||||
str = AZStd::basic_string<AZStd::wstring::value_type, AZStd::wstring::traits_type, Allocator>(static_cast<const AZStd::wstring::value_type*>(m_data), m_dataSize / 2);
|
||||
if (m_isEndianSwap)
|
||||
{
|
||||
AZStd::endian_swap(str.begin(), str.end());
|
||||
}
|
||||
return m_dataSize;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// math types
|
||||
void Read(AZ::Vector3& v) const;
|
||||
void Read(AZ::Vector4& v) const;
|
||||
void Read(AZ::Aabb& aabb) const;
|
||||
void Read(AZ::Obb& obb) const;
|
||||
void Read(AZ::Transform& tm) const;
|
||||
void Read(AZ::Matrix3x3& tm) const;
|
||||
void Read(AZ::Matrix4x4& tm) const;
|
||||
void Read(AZ::Quaternion& tm) const;
|
||||
void Read(AZ::Plane& plane) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// containers
|
||||
template<class Container>
|
||||
inline void Read(AZStd::insert_iterator<Container>& iter) const
|
||||
{
|
||||
typedef typename AZStd::insert_iterator<Container> InsertIterator;
|
||||
// we can specialize for contiguous_iterator_tag so have only 1 write for all elements
|
||||
const size_t elementSize = sizeof(InsertIterator::container_type::value_type);
|
||||
size_t numElements = m_dataSize / elementSize;
|
||||
AZ_Assert(m_dataSize % elementSize == 0, "Stored elements size doesn't match the read parameters!");
|
||||
Data elementEntry = *this;
|
||||
elementEntry.m_dataSize = elementSize;
|
||||
char* dataPtr = reinterpret_cast<char*>(m_data);
|
||||
for (size_t i = 0; i < numElements; ++i, ++iter)
|
||||
{
|
||||
typename InsertIterator::container_type::value_type value;
|
||||
elementEntry.m_data = dataPtr;
|
||||
Read(elementEntry, value);
|
||||
iter = value;
|
||||
dataPtr += elementSize;
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
const char* PrepareString(unsigned int& stringLength) const;
|
||||
};
|
||||
|
||||
typedef AZStd::delegate<void (u32 /*name*/, bool /*isOpen*/)> TagCallbackType;
|
||||
typedef AZStd::delegate<void (const Data&)> DataCallbackType;
|
||||
|
||||
AZ_CLASS_ALLOCATOR(DrillerSAXParser, OSAllocator, 0)
|
||||
DrillerSAXParser(const TagCallbackType& tcb, const DataCallbackType& dcb);
|
||||
/// Processes an input stream until all data is consumed (read returns 0 bytes).
|
||||
void ProcessStream(DrillerInputStream& stream);
|
||||
protected:
|
||||
|
||||
typedef vector<char>::type BufferType;
|
||||
BufferType m_buffer;
|
||||
TagCallbackType m_tagCallback;
|
||||
DataCallbackType m_dataCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
* DOM like parser, we will load the entire stream in memory (ProcessStream function).
|
||||
* Depending on the data size this can be very memory consuming.
|
||||
* \note DOM is used as reference we are NOT compliant with the DOM specs in any way.
|
||||
* IMPORTANT: All data is stored (for parsing) in the same order the events occurred
|
||||
* or the remote machine. Each next tad or data was recorded in the way. You can use
|
||||
* this as an event index.
|
||||
*/
|
||||
class DrillerDOMParser
|
||||
: public DrillerSAXParser
|
||||
{
|
||||
public:
|
||||
struct Node
|
||||
{
|
||||
typedef forward_list<Data>::type DataListType;
|
||||
typedef forward_list<Node>::type NodeListType;
|
||||
|
||||
u32 m_name;
|
||||
Node* m_parent;
|
||||
DataListType m_data;
|
||||
NodeListType m_tags;
|
||||
|
||||
/// Return a pointer to the first tag with specific name.
|
||||
const Node* GetTag(u32 tagName) const;
|
||||
/// Returns pointer to the first data entry with specific name. NULL if not data has been found.
|
||||
const Data* GetData(u32 dataName) const;
|
||||
/// Returns pointer to the first data entry with specific name. If it can't be found it will assert
|
||||
const Data* GetDataRequired(u32 dataName) const
|
||||
{
|
||||
const Data* dataNode = GetData(dataName);
|
||||
AZ_Assert(dataNode != NULL, "Data node in tag 0x%08x with name 0x%08x is required but missing!", m_name, dataName);
|
||||
return dataNode;
|
||||
}
|
||||
};
|
||||
|
||||
AZ_CLASS_ALLOCATOR(DrillerDOMParser, OSAllocator, 0)
|
||||
|
||||
DrillerDOMParser(bool isPersistentInputData = false);
|
||||
~DrillerDOMParser();
|
||||
/// return true if we are at top level of the tree and we can parse the data safely (there may be still more data, but it's top level only).
|
||||
bool CanParse() const { return m_topNode == &m_root; }
|
||||
|
||||
const Node* GetRootNode() const { return &m_root; }
|
||||
protected:
|
||||
Node m_root;
|
||||
Node* m_topNode;
|
||||
bool m_isPersistentInputData; ///< true if data that we process is persistent so we don't need to copy it internally, false otherwise.
|
||||
|
||||
void OnTag(u32 name, bool isOpen);
|
||||
void OnData(const Data& data);
|
||||
void DeleteNode(Node& node);
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for handling a Tag with a specific name. Handlers are kept in a hierarchy
|
||||
* with one required by DrillerSAXParserHandler to be able to handle tags at a root
|
||||
* level for the driller data stream.
|
||||
*/
|
||||
class DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
DrillerHandlerParser(bool isWarnOnUnsupportedTags = true)
|
||||
: m_isWarnOnUnsupportedTags(isWarnOnUnsupportedTags) {}
|
||||
|
||||
virtual ~DrillerHandlerParser() {}
|
||||
/// Enumerate all the child tags that we support for the tag we are handling. If the tag is not know you should return NULL
|
||||
virtual DrillerHandlerParser* OnEnterTag(u32 tagName) { (void)tagName; return NULL; }
|
||||
/// Exit tag you are not required to implement this, we always exist tags in order FILO.
|
||||
virtual void OnExitTag(DrillerHandlerParser* handler, u32 tagName) { (void)handler; (void)tagName; }
|
||||
/// Handle that data for the tag we are handling.
|
||||
virtual void OnData(const DrillerSAXParser::Data& dataNode) { (void)dataNode; }
|
||||
/// Return the warning state on unsupported tags (sometime you might want to warn usually) and sometimes not (if you load newer drills, etc.)
|
||||
inline bool IsWarnOnUnsupportedTags() const { return m_isWarnOnUnsupportedTags; }
|
||||
|
||||
protected:
|
||||
bool m_isWarnOnUnsupportedTags;
|
||||
};
|
||||
|
||||
/**
|
||||
* Processes a driller driller and dispatches the data based on the
|
||||
* the DrillerHandlerParser (handlers) and their ability to handle specific tags.
|
||||
* If a tag is NOT found as a child of the current one it will display a warning with the tag name
|
||||
* (useless it's allowed by DrillerHandlerParser::IsWarnOnUnsupportedTags) and process the stream
|
||||
* is a safe manner by skipping all the data and tags we can't handle.
|
||||
*/
|
||||
class DrillerSAXParserHandler
|
||||
: public DrillerSAXParser
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerSAXParserHandler, OSAllocator, 0)
|
||||
|
||||
DrillerSAXParserHandler(DrillerHandlerParser* rootHandler);
|
||||
|
||||
protected:
|
||||
|
||||
/// Called from DrillerSAXParser when we have an open tag.
|
||||
void OnTag(u32 name, bool isOpen);
|
||||
/// Called from DrillerSAXParser when we have data, which will be forwarded to the handler.
|
||||
void OnData(const DrillerSAXParser::Data& data);
|
||||
|
||||
typedef vector<DrillerHandlerParser*>::type DrillerHandlerStackType;
|
||||
DrillerHandlerStackType m_stack;
|
||||
};
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_DRILLER_STREAM_H
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,72 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_SYSTEM_FILE_BUS_H
|
||||
#define AZCORE_SYSTEM_FILE_BUS_H
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
/**
|
||||
* File IO interface. All events return true if we executed the
|
||||
* specific operation and no other code will be executed. If we return false
|
||||
* the normal code for the specific event will be executed.
|
||||
* IMPORTANT: We support multiple listeners with the idea that many systems can listen
|
||||
* for event. This interface allows to actually perform the operations, in such cases make
|
||||
* sure only one of the listeners provides this service (otherwise depending on registration
|
||||
* order service providers may change)
|
||||
* IMPORTANT: We don't provide any sync for the FileIOBus. We do that for a couple of reasons.
|
||||
* 1. If you will handle file IO youself or keeptrack of statistics you code will most likely already do that
|
||||
* 2. It is NOT safe to BusConnect/BusDisconnect while the FileIO is in use (this is why you should connect in advance)
|
||||
* otherwise if you provide service you can end up connecting in a middle of reads/writes/etc.
|
||||
*/
|
||||
class FileIO
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~FileIO() {}
|
||||
virtual bool OnOpen(SystemFile& file, const char* fileName, int mode, int platformFlags, bool& isFileOpened) = 0;
|
||||
virtual bool OnClose(SystemFile& file) = 0;
|
||||
virtual bool OnSeek(SystemFile& file, SystemFile::SizeType offset, SystemFile::SeekMode mode) = 0;
|
||||
virtual bool OnRead(SystemFile& file, SystemFile::SizeType byteSize, void* buffer, SystemFile::SizeType& numRead) = 0;
|
||||
virtual bool OnWrite(SystemFile& file, const void* buffer, SystemFile::SizeType byteSize, SystemFile::SizeType& numWritten) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<FileIO> FileIOBus;
|
||||
|
||||
/**
|
||||
* Interface for handling file io events. All events are syncronized
|
||||
*/
|
||||
class FileIOEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~FileIOEvents() {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
//TODO rbbaklov or zolniery look into why a recursive lock was not needed previously
|
||||
typedef AZStd::recursive_mutex MutexType; //< make sure all file events are thread safe as they will called from many threads
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* You will either have a file (SystemFile) pointer or fileName pointer to the file name.
|
||||
* \param fileName is provided when there is NO SystemFile object (when you call static functions).
|
||||
*/
|
||||
virtual void OnError(const SystemFile* file, const char* fileName, int errorCode) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<FileIOEvents> FileIOEventBus;
|
||||
}
|
||||
}
|
||||
#endif // AZCORE_SYSTEM_FILE_BUS_H
|
||||
#pragma once
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
@@ -101,7 +100,6 @@ bool SystemFile::Open(const char* fileName, int mode, int platformFlags)
|
||||
{
|
||||
if (strlen(fileName) > m_fileName.max_size())
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,17 +107,6 @@ bool SystemFile::Open(const char* fileName, int mode, int platformFlags)
|
||||
m_fileName = fileName;
|
||||
}
|
||||
|
||||
if (FileIOBus::HasHandlers())
|
||||
{
|
||||
bool isOpen = false;
|
||||
bool isHandled = false;
|
||||
EBUS_EVENT_RESULT(isHandled, FileIOBus, OnOpen, *this, m_fileName.c_str(), mode, platformFlags, isOpen);
|
||||
if (isHandled)
|
||||
{
|
||||
return isOpen;
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Assert(!IsOpen(), "This file (%s) is already open!", m_fileName.c_str());
|
||||
|
||||
return PlatformOpen(mode, platformFlags);
|
||||
@@ -133,31 +120,11 @@ bool SystemFile::ReOpen(int mode, int platformFlags)
|
||||
|
||||
void SystemFile::Close()
|
||||
{
|
||||
if (FileIOBus::HasHandlers())
|
||||
{
|
||||
bool isHandled = false;
|
||||
EBUS_EVENT_RESULT(isHandled, FileIOBus, OnClose, *this);
|
||||
if (isHandled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PlatformClose();
|
||||
}
|
||||
|
||||
void SystemFile::Seek(SeekSizeType offset, SeekMode mode)
|
||||
{
|
||||
if (FileIOBus::HasHandlers())
|
||||
{
|
||||
bool isHandled = false;
|
||||
EBUS_EVENT_RESULT(isHandled, FileIOBus, OnSeek, *this, offset, mode);
|
||||
if (isHandled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Platform::Seek(m_handle, this, offset, mode);
|
||||
}
|
||||
|
||||
@@ -178,33 +145,11 @@ AZ::u64 SystemFile::ModificationTime()
|
||||
|
||||
SystemFile::SizeType SystemFile::Read(SizeType byteSize, void* buffer)
|
||||
{
|
||||
if (FileIOBus::HasHandlers())
|
||||
{
|
||||
SizeType numRead = 0;
|
||||
bool isHandled = false;
|
||||
EBUS_EVENT_RESULT(isHandled, FileIOBus, OnRead, *this, byteSize, buffer, numRead);
|
||||
if (isHandled)
|
||||
{
|
||||
return numRead;
|
||||
}
|
||||
}
|
||||
|
||||
return Platform::Read(m_handle, this, byteSize, buffer);
|
||||
}
|
||||
|
||||
SystemFile::SizeType SystemFile::Write(const void* buffer, SizeType byteSize)
|
||||
{
|
||||
if (FileIOBus::HasHandlers())
|
||||
{
|
||||
SizeType numWritten = 0;
|
||||
bool isHandled = false;
|
||||
EBUS_EVENT_RESULT(isHandled, FileIOBus, OnWrite, *this, buffer, byteSize, numWritten);
|
||||
if (isHandled)
|
||||
{
|
||||
return numWritten;
|
||||
}
|
||||
}
|
||||
|
||||
return Platform::Write(m_handle, this, buffer, byteSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
|
||||
#include <AzCore/std/time.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
|
||||
@@ -26,30 +26,25 @@ using namespace AZ::Debug;
|
||||
// AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::AllocationRecords(unsigned char stackRecordLevels, bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
|
||||
AllocationRecords::AllocationRecords(unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
|
||||
: m_mode(AllocatorManager::Instance().m_defaultTrackingRecordMode)
|
||||
, m_isAutoIntegrityCheck(false)
|
||||
, m_isMarkUnallocatedMemory(isMarkUnallocatedMemory)
|
||||
, m_saveNames(false)
|
||||
, m_decodeImmediately(false)
|
||||
, m_numStackLevels(stackRecordLevels)
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
, m_memoryGuardSize(isMemoryGuard ? sizeof(Debug::GuardValue) : 0)
|
||||
#else
|
||||
, m_memoryGuardSize(0)
|
||||
#endif
|
||||
, m_requestedAllocs(0)
|
||||
, m_requestedBytes(0)
|
||||
, m_requestedBytesPeak(0)
|
||||
, m_allocatorName(allocatorName)
|
||||
{
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
m_memoryGuardSize = isMemoryGuard ? sizeof(Debug::GuardValue) : 0;
|
||||
#else
|
||||
(void)isMemoryGuard;
|
||||
m_memoryGuardSize = 0;
|
||||
#endif
|
||||
#if AZ_TRAIT_OS_HAS_CRITICAL_SECTION_SPIN_COUNT
|
||||
SetCriticalSectionSpinCount(DrillerEBusMutex::GetMutex().native_handle(), 4000);
|
||||
#endif
|
||||
// preallocate some buckets
|
||||
//m_records.rehash(20000);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~AllocationRecords
|
||||
@@ -73,7 +68,7 @@ AllocationRecords::~AllocationRecords()
|
||||
void
|
||||
AllocationRecords::lock()
|
||||
{
|
||||
DrillerEBusMutex::GetMutex().lock();
|
||||
m_recordsMutex.lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -82,7 +77,7 @@ AllocationRecords::lock()
|
||||
//=========================================================================
|
||||
bool AllocationRecords::try_lock()
|
||||
{
|
||||
return DrillerEBusMutex::GetMutex().try_lock();
|
||||
return m_recordsMutex.try_lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -92,7 +87,7 @@ bool AllocationRecords::try_lock()
|
||||
void
|
||||
AllocationRecords::unlock()
|
||||
{
|
||||
DrillerEBusMutex::GetMutex().unlock();
|
||||
m_recordsMutex.unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -117,7 +112,7 @@ AllocationRecords::RegisterAllocation(void* address, size_t byteSize, size_t ali
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
IntegrityCheckNoLock();
|
||||
IntegrityCheck();
|
||||
}
|
||||
|
||||
AZ_Assert(byteSize>sizeof(Debug::GuardValue), "Did you forget to add the extra MemoryGuardSize() bytes?");
|
||||
@@ -125,7 +120,11 @@ AllocationRecords::RegisterAllocation(void* address, size_t byteSize, size_t ali
|
||||
new(reinterpret_cast<char*>(address)+byteSize) Debug::GuardValue();
|
||||
}
|
||||
|
||||
Debug::AllocationRecordsType::pair_iter_bool iterBool = m_records.insert_key(address);
|
||||
Debug::AllocationRecordsType::pair_iter_bool iterBool;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
iterBool = m_records.insert_key(address);
|
||||
}
|
||||
|
||||
if (!iterBool.second)
|
||||
{
|
||||
@@ -210,7 +209,15 @@ AllocationRecords::RegisterAllocation(void* address, size_t byteSize, size_t ali
|
||||
|
||||
// statistics
|
||||
m_requestedBytes += byteSize;
|
||||
m_requestedBytesPeak = AZStd::GetMax(m_requestedBytesPeak, m_requestedBytes);
|
||||
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
|
||||
++m_requestedAllocs;
|
||||
|
||||
return &ai;
|
||||
@@ -220,8 +227,7 @@ AllocationRecords::RegisterAllocation(void* address, size_t byteSize, size_t ali
|
||||
// UnregisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
|
||||
void AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
|
||||
{
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
@@ -232,24 +238,38 @@ AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t a
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
|
||||
// We cannot assert if an allocation does not exist because our allocators start up way before the driller is started and the Allocator Records would be created.
|
||||
// It is currently impossible to actually track all allocations that happen before a certain point
|
||||
//AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
if (iter == m_records.end())
|
||||
AllocationInfo allocationInfo;
|
||||
{
|
||||
return;
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
// We cannot assert if an allocation does not exist because allocations may have been made before tracking was enabled.
|
||||
// It is currently impossible to actually track all allocations that happen before a certain point
|
||||
// AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
if (iter == m_records.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
allocationInfo = iter->second;
|
||||
m_records.erase(iter);
|
||||
|
||||
// try to be more aggressive and keep the memory footprint low.
|
||||
// \todo store the load factor at the last rehash to avoid unnecessary rehash
|
||||
if (m_records.load_factor() < 0.9f)
|
||||
{
|
||||
m_records.rehash(0);
|
||||
}
|
||||
}
|
||||
AllocatorManager::Instance().DebugBreak(address, iter->second);
|
||||
|
||||
|
||||
AllocatorManager::Instance().DebugBreak(address, allocationInfo);
|
||||
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
AZ_Assert(byteSize==0||byteSize==iter->second.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
|
||||
AZ_Assert(alignment==0||alignment==iter->second.m_alignment, "Mismatched alignment at deallocation! You supplied an invalid value!");
|
||||
AZ_Assert(byteSize==0||byteSize==allocationInfo.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
|
||||
AZ_Assert(alignment==0||alignment==allocationInfo.m_alignment, "Mismatched alignment at deallocation! You supplied an invalid value!");
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= iter->second.m_byteSize;
|
||||
m_requestedBytes -= allocationInfo.m_byteSize;
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
// memory guard
|
||||
@@ -258,18 +278,18 @@ AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t a
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheckNoLock();
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check current allocation
|
||||
char* guardAddress = reinterpret_cast<char*>(address)+iter->second.m_byteSize;
|
||||
char* guardAddress = reinterpret_cast<char*>(address)+allocationInfo.m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, iter->second, m_numStackLevels);
|
||||
printAlloc(address, allocationInfo, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
@@ -278,33 +298,26 @@ AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t a
|
||||
#endif
|
||||
|
||||
// delete allocation record
|
||||
if (iter->second.m_namesBlock)
|
||||
if (allocationInfo.m_namesBlock)
|
||||
{
|
||||
m_records.get_allocator().deallocate(iter->second.m_namesBlock, iter->second.m_namesBlockSize, 1);
|
||||
iter->second.m_namesBlock = nullptr;
|
||||
iter->second.m_namesBlockSize = 0;
|
||||
iter->second.m_name = nullptr;
|
||||
iter->second.m_fileName = nullptr;
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_namesBlock, allocationInfo.m_namesBlockSize, 1);
|
||||
allocationInfo.m_namesBlock = nullptr;
|
||||
allocationInfo.m_namesBlockSize = 0;
|
||||
allocationInfo.m_name = nullptr;
|
||||
allocationInfo.m_fileName = nullptr;
|
||||
}
|
||||
if (iter->second.m_stackFrames)
|
||||
if (allocationInfo.m_stackFrames)
|
||||
{
|
||||
m_records.get_allocator().deallocate(iter->second.m_stackFrames, sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1);
|
||||
iter->second.m_stackFrames = nullptr;
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_stackFrames, sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1);
|
||||
allocationInfo.m_stackFrames = nullptr;
|
||||
}
|
||||
|
||||
if (info)
|
||||
{
|
||||
*info = iter->second;
|
||||
*info = allocationInfo;
|
||||
}
|
||||
|
||||
m_records.erase(iter);
|
||||
|
||||
// try to be more aggressive and keep the memory footprint low.
|
||||
// \todo store the load factor at the last rehash to avoid unnecessary rehash
|
||||
if (m_records.load_factor()<0.9f)
|
||||
{
|
||||
m_records.rehash(0);
|
||||
}
|
||||
|
||||
// if requested set memory to a specific value.
|
||||
if (m_isMarkUnallocatedMemory)
|
||||
@@ -325,9 +338,14 @@ AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
AllocatorManager::Instance().DebugBreak(address, iter->second);
|
||||
AllocationInfo* allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
AZ_Assert(iter != m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
allocationInfo = &iter->second;
|
||||
}
|
||||
AllocatorManager::Instance().DebugBreak(address, *allocationInfo);
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
@@ -335,12 +353,12 @@ AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheckNoLock();
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check memory guard
|
||||
char* guardAddress = reinterpret_cast<char*>(address)+iter->second.m_byteSize;
|
||||
char* guardAddress = reinterpret_cast<char*>(address) + allocationInfo->m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
@@ -358,13 +376,19 @@ AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
#endif
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= iter->second.m_byteSize;
|
||||
m_requestedBytes -= allocationInfo->m_byteSize;
|
||||
m_requestedBytes += newSize;
|
||||
m_requestedBytesPeak = AZStd::GetMax(m_requestedBytesPeak, m_requestedBytes);
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
++m_requestedAllocs;
|
||||
|
||||
// update allocation size
|
||||
iter->second.m_byteSize = newSize;
|
||||
allocationInfo->m_byteSize = newSize;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -374,21 +398,20 @@ AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
void
|
||||
AllocationRecords::SetMode(Mode mode)
|
||||
{
|
||||
DrillerEBusMutex::GetMutex().lock();
|
||||
|
||||
if (mode==RECORD_NO_RECORDS)
|
||||
if (mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
m_records.clear();
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
m_records.clear();
|
||||
}
|
||||
m_requestedBytes = 0;
|
||||
m_requestedBytesPeak = 0;
|
||||
m_requestedAllocs = 0;
|
||||
}
|
||||
|
||||
AZ_Warning("Memory", m_mode!=RECORD_NO_RECORDS||mode==RECORD_NO_RECORDS, "Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations which were not recorded!");
|
||||
AZ_Warning("Memory", m_mode != RECORD_NO_RECORDS || mode == RECORD_NO_RECORDS, "Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations which were not recorded!");
|
||||
|
||||
m_mode = mode;
|
||||
|
||||
DrillerEBusMutex::GetMutex().unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -398,11 +421,14 @@ AllocationRecords::SetMode(Mode mode)
|
||||
void
|
||||
AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
|
||||
{
|
||||
DrillerEBusMutex::GetMutex().lock();
|
||||
// enumerate all allocations and stop if requested.
|
||||
// Since allocations can change during the iteration (code that prints out the records could allocate, which will
|
||||
// mutate m_records), we are going to make a copy and iterate the copy.
|
||||
const Debug::AllocationRecordsType recordsCopy = m_records;
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
recordsCopy = m_records;
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
if (!cb(iter->first, iter->second, m_numStackLevels))
|
||||
@@ -410,7 +436,6 @@ AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
|
||||
break;
|
||||
}
|
||||
}
|
||||
DrillerEBusMutex::GetMutex().unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -420,38 +445,29 @@ AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
|
||||
void
|
||||
AllocationRecords::IntegrityCheck() const
|
||||
{
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
DrillerEBusMutex::GetMutex().lock();
|
||||
|
||||
IntegrityCheckNoLock();
|
||||
|
||||
DrillerEBusMutex::GetMutex().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// IntegrityCheckNoLock
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::IntegrityCheckNoLock() const
|
||||
{
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = m_records.begin(); iter != m_records.end(); ++iter)
|
||||
{
|
||||
// check memory guard
|
||||
const char* guardAddress = reinterpret_cast<const char*>(iter->first)+ iter->second.m_byteSize;
|
||||
if (!reinterpret_cast<const Debug::GuardValue*>(guardAddress)->Validate())
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
// We have to turn off the integrity check at this point if we want to succesfully report the memory
|
||||
// stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
|
||||
// allocation done therein recurses this same code.
|
||||
*const_cast<bool*>(&m_isAutoIntegrityCheck) = false;
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(iter->first, iter->second, m_numStackLevels);
|
||||
AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
recordsCopy = m_records;
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
// check memory guard
|
||||
const char* guardAddress = reinterpret_cast<const char*>(iter->first)+ iter->second.m_byteSize;
|
||||
if (!reinterpret_cast<const Debug::GuardValue*>(guardAddress)->Validate())
|
||||
{
|
||||
// We have to turn off the integrity check at this point if we want to succesfully report the memory
|
||||
// stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
|
||||
// allocation done therein recurses this same code.
|
||||
*const_cast<bool*>(&m_isAutoIntegrityCheck) = false;
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(iter->first, iter->second, m_numStackLevels);
|
||||
AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -120,10 +120,9 @@ namespace AZ
|
||||
*/
|
||||
class AllocationRecords
|
||||
{
|
||||
friend class MemoryDriller;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AllocationRecords, OSAllocator, 0);
|
||||
|
||||
public:
|
||||
enum Mode : int
|
||||
{
|
||||
RECORD_NO_RECORDS, ///< Never record any information.
|
||||
@@ -178,7 +177,7 @@ namespace AZ
|
||||
/// Returns peak of requested memory. IMPORTANT: This is user requested memory! Any allocator overhead is NOT included.
|
||||
size_t RequestedBytesPeak() const { return m_requestedBytesPeak; }
|
||||
/// Reset the peak allocation to the current requested memory.
|
||||
void ResetPeakBytes() { m_requestedBytesPeak = m_requestedBytes; }
|
||||
void ResetPeakBytes() { m_requestedBytesPeak.store(m_requestedBytes); }
|
||||
/// Return requested user bytes. IMPORTANT: This is user requested memory! Any allocator overhead is NOT included.
|
||||
size_t RequestedBytes() const { return m_requestedBytes; }
|
||||
/// Returns total number of requested allocations.
|
||||
@@ -186,8 +185,6 @@ namespace AZ
|
||||
|
||||
const char* GetAllocatorName() const { return m_allocatorName; }
|
||||
|
||||
protected:
|
||||
|
||||
// @{ Allocation tracking management - we assume this functions are called with the lock locked.
|
||||
const AllocationInfo* RegisterAllocation(void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount);
|
||||
void UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info);
|
||||
@@ -195,9 +192,9 @@ namespace AZ
|
||||
void ResizeAllocation(void* address, size_t newSize);
|
||||
// @}
|
||||
|
||||
void IntegrityCheckNoLock() const;
|
||||
|
||||
protected:
|
||||
Debug::AllocationRecordsType m_records;
|
||||
AZStd::spin_mutex m_recordsMutex;
|
||||
Mode m_mode;
|
||||
bool m_isAutoIntegrityCheck;
|
||||
bool m_isMarkUnallocatedMemory; ///< True if we want to set value 0xcd in unallocated memory.
|
||||
@@ -205,9 +202,9 @@ namespace AZ
|
||||
bool m_decodeImmediately;
|
||||
unsigned char m_numStackLevels;
|
||||
unsigned int m_memoryGuardSize;
|
||||
size_t m_requestedAllocs;
|
||||
size_t m_requestedBytes;
|
||||
size_t m_requestedBytesPeak;
|
||||
AZStd::atomic<size_t> m_requestedAllocs;
|
||||
AZStd::atomic<size_t> m_requestedBytes;
|
||||
AZStd::atomic<size_t> m_requestedBytesPeak;
|
||||
|
||||
const char* m_allocatorName;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
#include <AzCore/Memory/MemoryDrillerBus.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
@@ -74,16 +73,24 @@ void AllocatorBase::PostCreate()
|
||||
}
|
||||
}
|
||||
|
||||
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
m_platformMemoryInstrumentationGroupId = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
|
||||
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationGroupId, GetDescription(), AZ::PlatformMemoryInstrumentation::m_groupRoot);
|
||||
#endif
|
||||
const auto debugConfig = GetDebugConfig();
|
||||
if (!debugConfig.m_excludeFromDebugging)
|
||||
{
|
||||
SetRecords(aznew Debug::AllocationRecords((unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory, GetName()));
|
||||
}
|
||||
|
||||
m_isReady = true;
|
||||
}
|
||||
|
||||
void AllocatorBase::PreDestroy()
|
||||
{
|
||||
Debug::AllocationRecords* allocatorRecords = GetRecords();
|
||||
if(allocatorRecords)
|
||||
{
|
||||
delete allocatorRecords;
|
||||
SetRecords(nullptr);
|
||||
}
|
||||
|
||||
if (m_registrationEnabled && AZ::AllocatorManager::IsReady())
|
||||
{
|
||||
AllocatorManager::Instance().UnRegisterAllocator(this);
|
||||
@@ -130,11 +137,11 @@ void AllocatorBase::ProfileAllocation(void* ptr, size_t byteSize, size_t alignme
|
||||
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
AZ::PlatformMemoryInstrumentation::Alloc(ptr, byteSize, 0, m_platformMemoryInstrumentationGroupId);
|
||||
#else
|
||||
EBUS_EVENT(AZ::Debug::MemoryDrillerBus, RegisterAllocation, this, ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord);
|
||||
#endif
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,37 +149,25 @@ void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t align
|
||||
{
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
AZ::PlatformMemoryInstrumentation::Free(ptr);
|
||||
#else
|
||||
EBUS_EVENT(AZ::Debug::MemoryDrillerBus, UnregisterAllocation, this, ptr, byteSize, alignment, info);
|
||||
#endif
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->UnregisterAllocation(ptr, byteSize, alignment, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocationBegin(void* ptr, size_t newSize)
|
||||
void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
|
||||
{
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
AZ::PlatformMemoryInstrumentation::ReallocBegin(ptr, newSize, m_platformMemoryInstrumentationGroupId);
|
||||
#else
|
||||
// Driller API intensionally not called, only End is required.
|
||||
AZ_UNUSED(ptr);
|
||||
AZ_UNUSED(newSize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocationEnd(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
AZ::PlatformMemoryInstrumentation::ReallocEnd(newPtr, newSize, 0);
|
||||
#else
|
||||
EBUS_EVENT(AZ::Debug::MemoryDrillerBus, ReallocateAllocation, this, ptr, newPtr, newSize, newAlignment);
|
||||
#endif
|
||||
Debug::AllocationInfo info;
|
||||
ProfileDeallocation(ptr, 0, 0, &info);
|
||||
ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +180,11 @@ void AllocatorBase::ProfileResize(void* ptr, size_t newSize)
|
||||
{
|
||||
if (newSize && m_isProfilingActive)
|
||||
{
|
||||
EBUS_EVENT(AZ::Debug::MemoryDrillerBus, ResizeAllocation, this, ptr, newSize);
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->ResizeAllocation(ptr, newSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/IAllocator.h>
|
||||
#include <AzCore/Memory/PlatformMemoryInstrumentation.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -103,16 +102,13 @@ namespace AZ
|
||||
|
||||
const char* m_name = nullptr;
|
||||
const char* m_desc = nullptr;
|
||||
Debug::AllocationRecords* m_records = nullptr; // Cached pointer to allocation records. Works together with the MemoryDriller.
|
||||
Debug::AllocationRecords* m_records = nullptr; // Cached pointer to allocation records
|
||||
size_t m_memoryGuardSize = 0;
|
||||
bool m_isLazilyCreated = false;
|
||||
bool m_isProfilingActive = false;
|
||||
bool m_isReady = false;
|
||||
bool m_canBeOverridden = true;
|
||||
bool m_registrationEnabled = true;
|
||||
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
uint16_t m_platformMemoryInstrumentationGroupId = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace Internal {
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Memory/AllocatorOverrideShim.h>
|
||||
#include <AzCore/Memory/MallocSchema.h>
|
||||
#include <AzCore/Memory/MemoryDrillerBus.h>
|
||||
|
||||
#include <AzCore/std/parallel/lock.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
@@ -215,8 +214,6 @@ AllocatorManager::RegisterAllocator(class IAllocator* alloc)
|
||||
#ifdef AZCORE_MEMORY_ENABLE_OVERRIDES
|
||||
ConfigureAllocatorOverrides(alloc);
|
||||
#endif
|
||||
|
||||
EBUS_EVENT(Debug::MemoryDrillerBus, RegisterAllocator, alloc);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -319,11 +316,6 @@ AllocatorManager::UnRegisterAllocator(class IAllocator* alloc)
|
||||
{
|
||||
AZStd::lock_guard<AZStd::mutex> lock(m_allocatorListMutex);
|
||||
|
||||
if (alloc->GetRecords())
|
||||
{
|
||||
EBUS_EVENT(Debug::MemoryDrillerBus, UnregisterAllocator, alloc);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_numAllocators; ++i)
|
||||
{
|
||||
if (m_allocators[i] == alloc)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <AzCore/Memory/BestFitExternalMapSchema.h>
|
||||
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Memory/MemoryDrillerBus.h>
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
@@ -79,8 +78,14 @@ AllocatorDebugConfig BestFitExternalMapAllocator::GetDebugConfig()
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type
|
||||
BestFitExternalMapAllocator::Allocate(size_type byteSize, size_type alignment, int flags, const char* name, const char* fileName, int lineNum, unsigned int suppressStackRecord)
|
||||
BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::Allocate(
|
||||
size_type byteSize,
|
||||
size_type alignment,
|
||||
int flags,
|
||||
[[maybe_unused]] const char* name,
|
||||
[[maybe_unused]] const char* fileName,
|
||||
[[maybe_unused]] int lineNum,
|
||||
unsigned int suppressStackRecord)
|
||||
{
|
||||
(void)suppressStackRecord;
|
||||
|
||||
@@ -89,17 +94,6 @@ BestFitExternalMapAllocator::Allocate(size_type byteSize, size_type alignment, i
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
|
||||
BestFitExternalMapAllocator::pointer_type address = m_schema->Allocate(byteSize, alignment, flags);
|
||||
if (address == nullptr)
|
||||
{
|
||||
if (!OnOutOfMemory(byteSize, alignment, flags, name, fileName, lineNum))
|
||||
{
|
||||
if (GetRecords())
|
||||
{
|
||||
EBUS_EVENT(Debug::MemoryDrillerBus, DumpAllAllocations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Assert(address != nullptr, "BestFitExternalMapAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace AZ
|
||||
namespace Debug
|
||||
{
|
||||
class AllocationRecords;
|
||||
class MemoryDriller;
|
||||
}
|
||||
|
||||
namespace AllocatorStorage
|
||||
@@ -83,7 +82,7 @@ namespace AZ
|
||||
/// Sets the number of entries to omit from the top of the callstack when recording stack traces.
|
||||
AllocatorDebugConfig& StackRecordLevels(int levels) { m_stackRecordLevels = levels; return *this; }
|
||||
|
||||
/// Set to true if this allocator should not have its records recorded and analyzed by systems like the MemoryDriller.
|
||||
/// Set to true if this allocator should not have its records recorded and analyzed.
|
||||
AllocatorDebugConfig& ExcludeFromDebugging(bool exclude = true) { m_excludeFromDebugging = exclude; return *this; }
|
||||
|
||||
/// Set to true if this allocator expands allocations with guard sections to detect overruns.
|
||||
@@ -207,8 +206,6 @@ namespace AZ
|
||||
|
||||
template<class Allocator>
|
||||
friend class AllocatorWrapper;
|
||||
|
||||
friend class Debug::MemoryDriller;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,291 +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/Memory/MemoryDriller.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
//=========================================================================
|
||||
// MemoryDriller
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
MemoryDriller::MemoryDriller(const Descriptor& desc)
|
||||
{
|
||||
(void)desc;
|
||||
BusConnect();
|
||||
|
||||
AllocatorManager::Instance().EnterProfilingMode();
|
||||
|
||||
{
|
||||
// Register all allocators that were created before the driller existed
|
||||
auto allocatorLock = AllocatorManager::Instance().LockAllocators();
|
||||
|
||||
for (int i = 0; i < AllocatorManager::Instance().GetNumAllocators(); ++i)
|
||||
{
|
||||
IAllocator* allocator = AllocatorManager::Instance().GetAllocator(i);
|
||||
RegisterAllocator(allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~MemoryDriller
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
MemoryDriller::~MemoryDriller()
|
||||
{
|
||||
BusDisconnect();
|
||||
AllocatorManager::Instance().ExitProfilingMode();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Start
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::Start(const Param* params, int numParams)
|
||||
{
|
||||
(void)params;
|
||||
(void)numParams;
|
||||
|
||||
// dump current allocations for all allocators with tracking
|
||||
auto allocatorLock = AllocatorManager::Instance().LockAllocators();
|
||||
for (int i = 0; i < AllocatorManager::Instance().GetNumAllocators(); ++i)
|
||||
{
|
||||
IAllocator* allocator = AllocatorManager::Instance().GetAllocator(i);
|
||||
if (auto records = allocator->GetRecords())
|
||||
{
|
||||
RegisterAllocatorOutput(allocator);
|
||||
const AllocationRecordsType& allocMap = records->GetMap();
|
||||
for (AllocationRecordsType::const_iterator allocIt = allocMap.begin(); allocIt != allocMap.end(); ++allocIt)
|
||||
{
|
||||
RegisterAllocationOutput(allocator, allocIt->first, &allocIt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Stop
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::Stop()
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterAllocator
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::RegisterAllocator(IAllocator* allocator)
|
||||
{
|
||||
// Ignore if our allocator is already registered
|
||||
if (allocator->GetRecords() != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto debugConfig = allocator->GetDebugConfig();
|
||||
|
||||
if (!debugConfig.m_excludeFromDebugging)
|
||||
{
|
||||
allocator->SetRecords(aznew Debug::AllocationRecords((unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory, allocator->GetName()));
|
||||
|
||||
m_allAllocatorRecords.push_back(allocator->GetRecords());
|
||||
|
||||
if (m_output == nullptr)
|
||||
{
|
||||
return; // we have no active output
|
||||
}
|
||||
RegisterAllocatorOutput(allocator);
|
||||
}
|
||||
}
|
||||
//=========================================================================
|
||||
// RegisterAllocatorOutput
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::RegisterAllocatorOutput(IAllocator* allocator)
|
||||
{
|
||||
auto records = allocator->GetRecords();
|
||||
m_output->BeginTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
m_output->BeginTag(AZ_CRC("RegisterAllocator", 0x19f08114));
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), allocator->GetName());
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), allocator);
|
||||
m_output->Write(AZ_CRC("Capacity", 0xb5e8b174), allocator->GetAllocationSource()->Capacity());
|
||||
m_output->Write(AZ_CRC("RecordsId", 0x7caaca88), records);
|
||||
if (records)
|
||||
{
|
||||
m_output->Write(AZ_CRC("RecordsMode", 0x764c147a), (char)records->GetMode());
|
||||
m_output->Write(AZ_CRC("NumStackLevels", 0xad9cff15), records->GetNumStackLevels());
|
||||
}
|
||||
m_output->EndTag(AZ_CRC("RegisterAllocator", 0x19f08114));
|
||||
m_output->EndTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// UnregisterAllocator
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::UnregisterAllocator(IAllocator* allocator)
|
||||
{
|
||||
auto allocatorRecords = allocator->GetRecords();
|
||||
AZ_Assert(allocatorRecords, "This allocator is not registered with the memory driller!");
|
||||
for (auto records : m_allAllocatorRecords)
|
||||
{
|
||||
if (records == allocatorRecords)
|
||||
{
|
||||
m_allAllocatorRecords.remove(records);
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete allocatorRecords;
|
||||
allocator->SetRecords(nullptr);
|
||||
|
||||
if (m_output == nullptr)
|
||||
{
|
||||
return; // we have no active output
|
||||
}
|
||||
m_output->BeginTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
m_output->Write(AZ_CRC("UnregisterAllocator", 0xb2b54f93), allocator);
|
||||
m_output->EndTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterAllocation
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::RegisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount)
|
||||
{
|
||||
auto records = allocator->GetRecords();
|
||||
if (records)
|
||||
{
|
||||
const AllocationInfo* info = records->RegisterAllocation(address, byteSize, alignment, name, fileName, lineNum, stackSuppressCount + 1);
|
||||
if (m_output == nullptr)
|
||||
{
|
||||
return; // we have no active output
|
||||
}
|
||||
RegisterAllocationOutput(allocator, address, info);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterAllocationOutput
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::RegisterAllocationOutput(IAllocator* allocator, void* address, const AllocationInfo* info)
|
||||
{
|
||||
auto records = allocator->GetRecords();
|
||||
m_output->BeginTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
m_output->BeginTag(AZ_CRC("RegisterAllocation", 0x992a9780));
|
||||
m_output->Write(AZ_CRC("RecordsId", 0x7caaca88), records);
|
||||
m_output->Write(AZ_CRC("Address", 0x0d4e6f81), address);
|
||||
if (info)
|
||||
{
|
||||
if (info->m_name)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), info->m_name);
|
||||
}
|
||||
m_output->Write(AZ_CRC("Alignment", 0x2cce1e5c), info->m_alignment);
|
||||
m_output->Write(AZ_CRC("Size", 0xf7c0246a), info->m_byteSize);
|
||||
if (info->m_fileName)
|
||||
{
|
||||
m_output->Write(AZ_CRC("FileName", 0x3c0be965), info->m_fileName);
|
||||
m_output->Write(AZ_CRC("FileLine", 0xb33c2395), info->m_lineNum);
|
||||
}
|
||||
// copy the stack frames directly, resolving the stack should happen later as this is a SLOW procedure.
|
||||
if (info->m_stackFrames)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Stack", 0x41a87b6a), info->m_stackFrames, info->m_stackFrames + records->GetNumStackLevels());
|
||||
}
|
||||
}
|
||||
m_output->EndTag(AZ_CRC("RegisterAllocation", 0x992a9780));
|
||||
m_output->EndTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// UnRegisterAllocation
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::UnregisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
|
||||
{
|
||||
auto records = allocator->GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->UnregisterAllocation(address, byteSize, alignment, info);
|
||||
|
||||
if (m_output == nullptr)
|
||||
{
|
||||
return; // we have no active output
|
||||
}
|
||||
m_output->BeginTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
m_output->BeginTag(AZ_CRC("UnRegisterAllocation", 0xea5dc4cd));
|
||||
m_output->Write(AZ_CRC("RecordsId", 0x7caaca88), records);
|
||||
m_output->Write(AZ_CRC("Address", 0x0d4e6f81), address);
|
||||
m_output->EndTag(AZ_CRC("UnRegisterAllocation", 0xea5dc4cd));
|
||||
m_output->EndTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReallocateAllocation
|
||||
// [10/1/2018]
|
||||
//=========================================================================
|
||||
void MemoryDriller::ReallocateAllocation(IAllocator* allocator, void* prevAddress, void* newAddress, size_t newByteSize, size_t newAlignment)
|
||||
{
|
||||
AllocationInfo info;
|
||||
UnregisterAllocation(allocator, prevAddress, 0, 0, &info);
|
||||
RegisterAllocation(allocator, newAddress, newByteSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ResizeAllocation
|
||||
// [2/6/2013]
|
||||
//=========================================================================
|
||||
void MemoryDriller::ResizeAllocation(IAllocator* allocator, void* address, size_t newSize)
|
||||
{
|
||||
auto records = allocator->GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->ResizeAllocation(address, newSize);
|
||||
|
||||
if (m_output == nullptr)
|
||||
{
|
||||
return; // we have no active output
|
||||
}
|
||||
m_output->BeginTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
m_output->BeginTag(AZ_CRC("ResizeAllocation", 0x8a9c78dc));
|
||||
m_output->Write(AZ_CRC("RecordsId", 0x7caaca88), records);
|
||||
m_output->Write(AZ_CRC("Address", 0x0d4e6f81), address);
|
||||
m_output->Write(AZ_CRC("Size", 0xf7c0246a), newSize);
|
||||
m_output->EndTag(AZ_CRC("ResizeAllocation", 0x8a9c78dc));
|
||||
m_output->EndTag(AZ_CRC("MemoryDriller", 0x1b31269d));
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryDriller::DumpAllAllocations()
|
||||
{
|
||||
// Create a copy so allocations done during the printing dont end up affecting the container
|
||||
const AZStd::list<Debug::AllocationRecords*, OSStdAllocator> allocationRecords = m_allAllocatorRecords;
|
||||
|
||||
for (auto records : allocationRecords)
|
||||
{
|
||||
// Skip if we have had no allocations made
|
||||
if (records->RequestedAllocs())
|
||||
{
|
||||
records->EnumerateAllocations(AZ::Debug::PrintAllocationsCB(true, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,71 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_MEMORY_DRILLER_H
|
||||
#define AZCORE_MEMORY_DRILLER_H 1
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Memory/MemoryDrillerBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
struct StackFrame;
|
||||
|
||||
/**
|
||||
* Trace messages driller class
|
||||
*/
|
||||
class MemoryDriller
|
||||
: public Driller
|
||||
, public MemoryDrillerBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MemoryDriller, OSAllocator, 0)
|
||||
|
||||
// TODO: Centralized settings for memory tracking.
|
||||
struct Descriptor
|
||||
{
|
||||
};
|
||||
|
||||
MemoryDriller(const Descriptor& desc = Descriptor());
|
||||
~MemoryDriller();
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller
|
||||
const char* GroupName() const override { return "SystemDrillers"; }
|
||||
const char* GetName() const override { return "MemoryDriller"; }
|
||||
const char* GetDescription() const override { return "Reports all allocators and memory allocations."; }
|
||||
void Start(const Param* params = NULL, int numParams = 0) override;
|
||||
void Stop() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MemoryDrillerBus
|
||||
void RegisterAllocator(IAllocator* allocator) override;
|
||||
void UnregisterAllocator(IAllocator* allocator) override;
|
||||
|
||||
void RegisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount) override;
|
||||
void UnregisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, AllocationInfo* info) override;
|
||||
void ReallocateAllocation(IAllocator* allocator, void* prevAddress, void* newAddress, size_t newByteSize, size_t newAlignment) override;
|
||||
void ResizeAllocation(IAllocator* allocator, void* address, size_t newSize) override;
|
||||
|
||||
void DumpAllAllocations() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RegisterAllocatorOutput(IAllocator* allocator);
|
||||
void RegisterAllocationOutput(IAllocator* allocator, void* address, const AllocationInfo* info);
|
||||
private:
|
||||
// Store a list of all of our allocator records so we can dump them all without having to know about the allocators
|
||||
AZStd::list<Debug::AllocationRecords*, OSStdAllocator> m_allAllocatorRecords;
|
||||
};
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_MEMORY_DRILLER_H
|
||||
#pragma once
|
||||
@@ -1,52 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_MEMORY_DRILLER_BUS_H
|
||||
#define AZCORE_MEMORY_DRILLER_BUS_H 1
|
||||
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class IAllocator;
|
||||
namespace Debug
|
||||
{
|
||||
//class AllocationRecords;
|
||||
struct AllocationInfo;
|
||||
|
||||
/**
|
||||
* Memory allocations driller message.
|
||||
*
|
||||
* We use a driller bus so all messages are sending in exclusive matter no other driller messages
|
||||
* can be triggered at that moment, so we already preserve the calling order. You can assume
|
||||
* all access code in the driller framework in guarded. You can manually lock the driller mutex are you
|
||||
* use by using \ref AZ::Debug::DrillerEBusMutex.
|
||||
*/
|
||||
class MemoryDrillerMessages
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~MemoryDrillerMessages() {}
|
||||
|
||||
/// Register allocation (with customizable tracking settings - TODO: we should centralize this settings and remove them from here)
|
||||
virtual void RegisterAllocator(IAllocator* allocator) = 0;
|
||||
virtual void UnregisterAllocator(IAllocator* allocator) = 0;
|
||||
|
||||
virtual void RegisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount) = 0;
|
||||
virtual void UnregisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, AllocationInfo* info) = 0;
|
||||
virtual void ReallocateAllocation(IAllocator* allocator, void* prevAddress, void* newAddress, size_t newByteSize, size_t newAlignment) = 0;
|
||||
virtual void ResizeAllocation(IAllocator* allocator, void* address, size_t newSize) = 0;
|
||||
|
||||
virtual void DumpAllAllocations() = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<MemoryDrillerMessages> MemoryDrillerBus;
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_MEMORY_DRILLER_BUS_H
|
||||
#pragma once
|
||||
@@ -20,7 +20,7 @@ namespace AZ
|
||||
* OS allocator should be used for direct OS allocations (C heap)
|
||||
* It's memory usage is NOT tracked. If you don't create this allocator, it will be implicitly
|
||||
* created by the SystemAllocator when it is needed. In addition this allocator is used for
|
||||
* debug data (like drillers, memory trackng, etc.)
|
||||
* debug data (like memory tracking, etc.)
|
||||
*/
|
||||
class OSAllocator
|
||||
: public AllocatorBase
|
||||
|
||||
@@ -1,42 +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/AzCore_Traits_Platform.h>
|
||||
|
||||
#if AZ_TRAIT_OS_MEMORY_INSTRUMENTATION && !defined(_RELEASE)
|
||||
#define PLATFORM_MEMORY_INSTRUMENTATION_ENABLED 1
|
||||
#else
|
||||
#define PLATFORM_MEMORY_INSTRUMENTATION_ENABLED 0
|
||||
#endif
|
||||
|
||||
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
/**
|
||||
* PlatformMemoryInstrumentation - Abstraction layer for platform specific memory instrumentation.
|
||||
*/
|
||||
class PlatformMemoryInstrumentation
|
||||
{
|
||||
public:
|
||||
static uint16_t GetNextGroupId() { return m_nextGroupId++; };
|
||||
static void RegisterGroup(uint16_t id, const char* name, uint16_t parentGroup);
|
||||
static void Alloc(const void* ptr, uint64_t size, uint32_t padding, uint16_t group);
|
||||
static void Free(const void* ptr);
|
||||
static void ReallocBegin(const void* origPtr, uint64_t size, uint16_t group);
|
||||
static void ReallocEnd(const void* newPtr, uint64_t size, uint32_t padding);
|
||||
static const uint16_t m_groupRoot;
|
||||
static uint16_t m_nextGroupId;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
|
||||
@@ -12,9 +12,6 @@
|
||||
#include <AzCore/Memory/PoolSchema.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
|
||||
#include <AzCore/Memory/MemoryDrillerBus.h>
|
||||
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
template<class Allocator>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Memory/MemoryDrillerBus.h>
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
@@ -248,14 +247,6 @@ SystemAllocator::Allocate(size_type byteSize, size_type alignment, int flags, co
|
||||
if (address == nullptr)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedDown(byteSize); // restore original size
|
||||
|
||||
if (!OnOutOfMemory(byteSize, alignment, flags, name, fileName, lineNum))
|
||||
{
|
||||
if (GetRecords())
|
||||
{
|
||||
EBUS_EVENT(Debug::MemoryDrillerBus, DumpAllAllocations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Assert(address != nullptr, "SystemAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Debug/AssetTracking.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/parallel/binary_semaphore.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
#include <AzCore/Debug/BudgetTracker.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Memory/MemoryDriller.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
|
||||
#if defined(HAVE_BENCHMARK)
|
||||
@@ -39,7 +37,6 @@ namespace UnitTest
|
||||
*/
|
||||
class AllocatorsBase
|
||||
{
|
||||
AZ::Debug::DrillerManager* m_drillerManager;
|
||||
bool m_ownsAllocator{};
|
||||
public:
|
||||
|
||||
@@ -47,8 +44,7 @@ namespace UnitTest
|
||||
|
||||
void SetupAllocator(const AZ::SystemAllocator::Descriptor& allocatorDesc = {})
|
||||
{
|
||||
m_drillerManager = AZ::Debug::DrillerManager::Create();
|
||||
m_drillerManager->Register(aznew AZ::Debug::MemoryDriller);
|
||||
AZ::AllocatorManager::Instance().EnterProfilingMode();
|
||||
AZ::AllocatorManager::Instance().SetDefaultTrackingMode(AZ::Debug::AllocationRecords::RECORD_FULL);
|
||||
|
||||
// Only create the SystemAllocator if it s not ready
|
||||
@@ -68,9 +64,9 @@ namespace UnitTest
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
m_ownsAllocator = false;
|
||||
AZ::Debug::DrillerManager::Destroy(m_drillerManager);
|
||||
|
||||
AZ::AllocatorManager::Instance().SetDefaultTrackingMode(AZ::Debug::AllocationRecords::RECORD_NO_RECORDS);
|
||||
AZ::AllocatorManager::Instance().ExitProfilingMode();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -93,8 +89,7 @@ namespace UnitTest
|
||||
* Helper class to handle the boiler plate of setting up a test fixture that uses the system allocators
|
||||
* If you wish to do additional setup and tear down be sure to call the base class SetUp first and TearDown
|
||||
* last.
|
||||
* By default memory tracking through driller is enabled.
|
||||
* Defaults to a heap size of 15 MB
|
||||
* By default memory tracking is enabled.
|
||||
*/
|
||||
|
||||
class AllocatorsTestFixture
|
||||
@@ -123,8 +118,7 @@ namespace UnitTest
|
||||
* Helper class to handle the boiler plate of setting up a benchmark fixture that uses the system allocators
|
||||
* If you wish to do additional setup and tear down be sure to call the base class SetUp first and TearDown
|
||||
* last.
|
||||
* By default memory tracking through driller is disabled.
|
||||
* Defaults to a heap size of 15 MB
|
||||
* By default memory tracking is enabled.
|
||||
*/
|
||||
class AllocatorsBenchmarkFixture
|
||||
: public ::benchmark::Fixture
|
||||
|
||||
@@ -92,10 +92,6 @@ set(FILES
|
||||
Compression/Compression.h
|
||||
Compression/zstd_compression.cpp
|
||||
Compression/zstd_compression.h
|
||||
Debug/AssetTracking.cpp
|
||||
Debug/AssetTracking.h
|
||||
Debug/AssetTrackingTypesImpl.h
|
||||
Debug/AssetTrackingTypes.h
|
||||
Debug/Budget.h
|
||||
Debug/Budget.cpp
|
||||
Debug/BudgetTracker.h
|
||||
@@ -111,18 +107,10 @@ set(FILES
|
||||
Debug/ProfilerReflection.cpp
|
||||
Debug/ProfilerReflection.h
|
||||
Debug/StackTracer.h
|
||||
Debug/EventTrace.h
|
||||
Debug/EventTrace.cpp
|
||||
Debug/EventTraceDriller.h
|
||||
Debug/EventTraceDriller.cpp
|
||||
Debug/EventTraceDrillerBus.h
|
||||
Debug/Timer.h
|
||||
Debug/Trace.cpp
|
||||
Debug/Trace.h
|
||||
Debug/TraceMessageBus.h
|
||||
Debug/TraceMessagesDriller.cpp
|
||||
Debug/TraceMessagesDriller.h
|
||||
Debug/TraceMessagesDrillerBus.h
|
||||
Debug/TraceReflection.cpp
|
||||
Debug/TraceReflection.h
|
||||
DOM/DomBackend.cpp
|
||||
@@ -134,14 +122,6 @@ set(FILES
|
||||
DOM/Backends/JSON/JsonBackend.h
|
||||
DOM/Backends/JSON/JsonSerializationUtils.cpp
|
||||
DOM/Backends/JSON/JsonSerializationUtils.h
|
||||
Driller/DefaultStringPool.h
|
||||
Driller/Driller.cpp
|
||||
Driller/Driller.h
|
||||
Driller/DrillerBus.cpp
|
||||
Driller/DrillerBus.h
|
||||
Driller/DrillerRootHandler.h
|
||||
Driller/Stream.cpp
|
||||
Driller/Stream.h
|
||||
EBus/BusImpl.h
|
||||
EBus/EBus.h
|
||||
EBus/EBusEnvironment.cpp
|
||||
@@ -178,7 +158,6 @@ set(FILES
|
||||
IO/CompressorZStd.h
|
||||
IO/FileIO.cpp
|
||||
IO/FileIO.h
|
||||
IO/FileIOEventBus.h
|
||||
IO/FileReader.cpp
|
||||
IO/FileReader.h
|
||||
IO/IOUtils.h
|
||||
@@ -404,16 +383,12 @@ set(FILES
|
||||
Memory/Memory.h
|
||||
Memory/MemoryComponent.cpp
|
||||
Memory/MemoryComponent.h
|
||||
Memory/MemoryDriller.cpp
|
||||
Memory/MemoryDriller.h
|
||||
Memory/MemoryDrillerBus.h
|
||||
Memory/nedmalloc.inl
|
||||
Memory/NewAndDelete.inl
|
||||
Memory/OSAllocator.cpp
|
||||
Memory/OSAllocator.h
|
||||
Memory/OverrunDetectionAllocator.cpp
|
||||
Memory/OverrunDetectionAllocator.h
|
||||
Memory/PlatformMemoryInstrumentation.h
|
||||
Memory/PoolAllocator.h
|
||||
Memory/PoolSchema.cpp
|
||||
Memory/PoolSchema.h
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#ifndef AZSTD_THREAD_BUS_H
|
||||
#define AZSTD_THREAD_BUS_H 1
|
||||
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
@@ -32,24 +32,7 @@ namespace AZStd
|
||||
virtual void OnThreadExit(const AZStd::thread::id& id) = 0;
|
||||
};
|
||||
|
||||
//! Thread events driller bus - only "drillers" (profilers) should connect to this.
|
||||
//! A global mutex that includes a lock on the memory manager and other driller busses
|
||||
//! is held during dispatch, and listeners are expected to do no allocation
|
||||
//! or thread workloads or blocking or mutex operations of their own - only dump the data to
|
||||
//! network or file ASAP.
|
||||
//! DO NOT USE this bus unless you are a profiler capture system, use the ThreadEvents / ThreadBus instead
|
||||
class ThreadDrillerEvents
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
/// Called when we enter a thread, optional thread_desc is provided when the use provides one.
|
||||
virtual void OnThreadEnter(const AZStd::thread::id& id, const AZStd::thread_desc* desc) = 0;
|
||||
/// Called when we exit a thread.
|
||||
virtual void OnThreadExit(const AZStd::thread::id& id) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<ThreadEvents> ThreadEventBus;
|
||||
typedef AZ::EBus<ThreadDrillerEvents> ThreadDrillerEventBus;
|
||||
}
|
||||
|
||||
#endif // AZSTD_THREAD_BUS_H
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
|
||||
@@ -87,7 +86,6 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
|
||||
}
|
||||
else
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, EINVAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -103,7 +101,6 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
|
||||
{
|
||||
if (isApkFile)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, ENOSPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -125,7 +122,6 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
|
||||
|
||||
if (m_handle == PlatformSpecificInvalidHandle)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -168,22 +164,8 @@ namespace Platform::Internal
|
||||
entry = readdir(dir);
|
||||
}
|
||||
|
||||
int lastError = errno;
|
||||
if (lastError != 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, filter, lastError);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
int lastError = errno;
|
||||
if (lastError != ENOENT)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, filter, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindFilesInApk(const char* filter, const SystemFile::FindFileCB& cb)
|
||||
@@ -233,11 +215,7 @@ namespace Platform
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
off_t result = fseeko(handle, static_cast<off_t>(offset), mode);
|
||||
if (result != 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
}
|
||||
fseeko(handle, static_cast<off_t>(offset), mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +226,6 @@ namespace Platform
|
||||
off_t result = ftello(handle);
|
||||
if (result == (off_t)-1)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
return 0;
|
||||
}
|
||||
return aznumeric_cast<SizeType>(result);
|
||||
@@ -292,7 +269,6 @@ namespace Platform
|
||||
|
||||
if (bytesRead != bytesToRead && ferror(handle))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -311,7 +287,6 @@ namespace Platform
|
||||
|
||||
if (bytesWritten != bytesToWrite && ferror(handle))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -325,10 +300,7 @@ namespace Platform
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
if (fflush(handle) != 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
}
|
||||
fflush(handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +319,6 @@ namespace Platform
|
||||
struct stat fileStat;
|
||||
if (stat(fileName, &fileStat) < 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, 0);
|
||||
return 0;
|
||||
}
|
||||
return static_cast<SizeType>(fileStat.st_size);
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.h>
|
||||
|
||||
@@ -44,21 +44,7 @@ namespace AZ::IO::Platform
|
||||
entry = readdir(dir);
|
||||
}
|
||||
|
||||
int lastError = errno;
|
||||
if (lastError != 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, filter, lastError);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
int lastError = errno;
|
||||
if (lastError != ENOENT)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, filter, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
@@ -130,7 +129,6 @@ namespace Platform
|
||||
int result = remove(fileName);
|
||||
if (result != 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, result);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -142,7 +140,6 @@ namespace Platform
|
||||
int result = rename(sourceFileName, targetFileName);
|
||||
if (result)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, sourceFileName, result);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -198,10 +195,6 @@ namespace Platform
|
||||
}
|
||||
azstrcpy(dirPath, AZ_MAX_PATH_LEN, dirName);
|
||||
bool success = CreateDirRecursive(dirPath);
|
||||
if (!success)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, dirName, errno);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
return false;
|
||||
|
||||
-2
@@ -35,7 +35,6 @@ namespace AZStd
|
||||
|
||||
destroy_thread_info(ti);
|
||||
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id());
|
||||
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadExit, this_thread::get_id());
|
||||
pthread_exit(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -88,7 +87,6 @@ namespace AZStd
|
||||
Platform::PostCreateThread(tId, name, cpuId);
|
||||
|
||||
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadEnter, thread::id(tId), desc);
|
||||
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadEnter, thread::id(tId), desc);
|
||||
return tId;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-21
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
@@ -61,7 +60,6 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
|
||||
}
|
||||
else
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -88,7 +86,6 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
|
||||
|
||||
if (m_handle == PlatformSpecificInvalidHandle)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, errno);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -119,11 +116,7 @@ namespace Platform
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
int result = lseek(handle, offset, mode);
|
||||
if (result == -1)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
}
|
||||
lseek(handle, offset, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,10 +125,6 @@ namespace Platform
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
off_t result = lseek(handle, 0, SEEK_CUR);
|
||||
if (result == (off_t)-1)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
}
|
||||
return aznumeric_cast<SizeType>(result);
|
||||
}
|
||||
|
||||
@@ -149,14 +138,12 @@ namespace Platform
|
||||
off_t current = lseek(handle, 0, SEEK_CUR);
|
||||
if (current == (off_t)-1)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, current);
|
||||
return false;
|
||||
}
|
||||
|
||||
off_t end = lseek(handle, 0, SEEK_END);
|
||||
if (end == (off_t)-1)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, end);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -191,7 +178,6 @@ namespace Platform
|
||||
ssize_t bytesRead = read(handle, buffer, byteSize);
|
||||
if (bytesRead == -1)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
return 0;
|
||||
}
|
||||
return bytesRead;
|
||||
@@ -207,7 +193,6 @@ namespace Platform
|
||||
ssize_t result = write(handle, buffer, byteSize);
|
||||
if (result == -1)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
@@ -221,10 +206,7 @@ namespace Platform
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
#if AZ_TRAIT_SYSTEMFILE_FSYNC_IS_DEFINED
|
||||
if (fsync(handle) != 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, errno);
|
||||
}
|
||||
fsync(handle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -236,7 +218,6 @@ namespace Platform
|
||||
struct stat stat;
|
||||
if (fstat(handle, &stat) < 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, 0);
|
||||
return 0;
|
||||
}
|
||||
return stat.st_size;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/Debug/TraceMessagesDrillerBus.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/std/string/fixed_string.h>
|
||||
|
||||
@@ -186,8 +185,6 @@ namespace AZ::Debug
|
||||
|
||||
Debug::Trace::Instance().PrintCallstack(nullptr, 0, ExceptionInfo->ContextRecord);
|
||||
|
||||
EBUS_EVENT(Debug::TraceMessageDrillerBus, OnException, message);
|
||||
|
||||
bool result = false;
|
||||
EBUS_EVENT_RESULT(result, Debug::TraceMessageBus, OnException, message);
|
||||
if (result)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
|
||||
@@ -142,7 +141,6 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
|
||||
|
||||
if (m_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, (int)GetLastError());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -160,10 +158,7 @@ void SystemFile::PlatformClose()
|
||||
{
|
||||
if (m_handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
if (!CloseHandle(m_handle))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, (int)GetLastError());
|
||||
}
|
||||
CloseHandle(m_handle);
|
||||
m_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -177,7 +172,7 @@ namespace Platform
|
||||
{
|
||||
using FileHandleType = AZ::IO::SystemFile::FileHandleType;
|
||||
|
||||
void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode)
|
||||
void Seek(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
@@ -185,14 +180,11 @@ namespace Platform
|
||||
LARGE_INTEGER distToMove;
|
||||
distToMove.QuadPart = offset;
|
||||
|
||||
if (!SetFilePointerEx(handle, distToMove, 0, dwMoveMethod))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
}
|
||||
SetFilePointerEx(handle, distToMove, 0, dwMoveMethod);
|
||||
}
|
||||
}
|
||||
|
||||
SystemFile::SizeType Tell(FileHandleType handle, const SystemFile* systemFile)
|
||||
SystemFile::SizeType Tell(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
@@ -202,7 +194,6 @@ namespace Platform
|
||||
LARGE_INTEGER newFilePtr;
|
||||
if (!SetFilePointerEx(handle, distToMove, &newFilePtr, FILE_CURRENT))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -212,7 +203,7 @@ namespace Platform
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Eof(FileHandleType handle, const SystemFile* systemFile)
|
||||
bool Eof(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
@@ -222,14 +213,12 @@ namespace Platform
|
||||
LARGE_INTEGER currentFilePtr;
|
||||
if (!SetFilePointerEx(handle, zero, ¤tFilePtr, FILE_CURRENT))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE_STANDARD_INFO fileInfo;
|
||||
if (!GetFileInformationByHandleEx(handle, FileStandardInfo, &fileInfo, sizeof(fileInfo)))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -239,14 +228,13 @@ namespace Platform
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::u64 ModificationTime(FileHandleType handle, const SystemFile* systemFile)
|
||||
AZ::u64 ModificationTime(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
FILE_BASIC_INFO fileInfo;
|
||||
if (!GetFileInformationByHandleEx(handle, FileBasicInfo, &fileInfo, sizeof(fileInfo)))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -263,7 +251,7 @@ namespace Platform
|
||||
return 0;
|
||||
}
|
||||
|
||||
SystemFile::SizeType Read(FileHandleType handle, const SystemFile* systemFile, SizeType byteSize, void* buffer)
|
||||
SystemFile::SizeType Read(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile, SizeType byteSize, void* buffer)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
@@ -271,7 +259,6 @@ namespace Platform
|
||||
DWORD nNumberOfBytesToRead = (DWORD)byteSize;
|
||||
if (!ReadFile(handle, buffer, nNumberOfBytesToRead, &dwNumBytesRead, 0))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
return static_cast<SizeType>(dwNumBytesRead);
|
||||
@@ -280,7 +267,7 @@ namespace Platform
|
||||
return 0;
|
||||
}
|
||||
|
||||
SystemFile::SizeType Write(FileHandleType handle, const SystemFile* systemFile, const void* buffer, SizeType byteSize)
|
||||
SystemFile::SizeType Write(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile, const void* buffer, SizeType byteSize)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
@@ -288,7 +275,6 @@ namespace Platform
|
||||
DWORD nNumberOfBytesToWrite = (DWORD)byteSize;
|
||||
if (!WriteFile(handle, buffer, nNumberOfBytesToWrite, &dwNumBytesWritten, 0))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
return static_cast<SizeType>(dwNumBytesWritten);
|
||||
@@ -297,25 +283,21 @@ namespace Platform
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Flush(FileHandleType handle, const SystemFile* systemFile)
|
||||
void Flush(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
if (!FlushFileBuffers(handle))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
}
|
||||
FlushFileBuffers(handle);
|
||||
}
|
||||
}
|
||||
|
||||
SystemFile::SizeType Length(FileHandleType handle, const SystemFile* systemFile)
|
||||
SystemFile::SizeType Length(FileHandleType handle, [[maybe_unused]] const SystemFile* systemFile)
|
||||
{
|
||||
if (handle != PlatformSpecificInvalidHandle)
|
||||
{
|
||||
LARGE_INTEGER size;
|
||||
if (!GetFileSizeEx(handle, &size))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, systemFile, nullptr, (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -341,7 +323,6 @@ namespace Platform
|
||||
{
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hFile;
|
||||
int lastError;
|
||||
|
||||
AZ::IO::FixedMaxPathWString filterW;
|
||||
AZStd::to_wstring(filterW, filter);
|
||||
@@ -367,20 +348,7 @@ namespace Platform
|
||||
cb(fileName, (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
|
||||
}
|
||||
|
||||
lastError = (int)GetLastError();
|
||||
FindClose(hFile);
|
||||
if (lastError != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, lastError);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lastError = (int)GetLastError();
|
||||
if (lastError != ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, filter, lastError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,15 +362,11 @@ namespace Platform
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE_BASIC_INFO fileInfo{};
|
||||
if (!GetFileInformationByHandleEx(handle, FileBasicInfo, &fileInfo, sizeof(fileInfo)))
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
|
||||
}
|
||||
GetFileInformationByHandleEx(handle, FileBasicInfo, &fileInfo, sizeof(fileInfo));
|
||||
|
||||
CloseHandle(handle);
|
||||
|
||||
@@ -434,10 +398,6 @@ namespace Platform
|
||||
fileSize.HighPart = data.nFileSizeHigh;
|
||||
len = aznumeric_cast<SizeType>(fileSize.QuadPart);
|
||||
}
|
||||
else
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -448,7 +408,6 @@ namespace Platform
|
||||
AZStd::to_wstring(fileNameW, fileName);
|
||||
if (DeleteFileW(fileNameW.c_str()) == 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -463,7 +422,6 @@ namespace Platform
|
||||
AZStd::to_wstring(targetFileNameW, targetFileName);
|
||||
if (MoveFileExW(sourceFileNameW.c_str(), targetFileNameW.c_str(), overwrite ? MOVEFILE_REPLACE_EXISTING : 0) == 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, sourceFileName, (int)GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -503,10 +461,6 @@ namespace Platform
|
||||
AZ::IO::FixedMaxPathWString dirNameW;
|
||||
AZStd::to_wstring(dirNameW, dirName);
|
||||
bool success = CreateDirRecursive(dirNameW);
|
||||
if (!success)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, dirName, (int)GetLastError());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
return false;
|
||||
|
||||
-2
@@ -38,7 +38,6 @@ namespace AZStd
|
||||
destroy_thread_info(ti);
|
||||
|
||||
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to client listeners
|
||||
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to the profiler.
|
||||
|
||||
return Platform::PostThreadRun();
|
||||
}
|
||||
@@ -73,7 +72,6 @@ namespace AZStd
|
||||
}
|
||||
|
||||
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadEnter, thread::id(*id), desc);
|
||||
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadEnter, thread::id(*id), desc);
|
||||
|
||||
::ResumeThread(hThread);
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.h>
|
||||
|
||||
@@ -44,21 +44,7 @@ namespace AZ::IO::Platform
|
||||
entry = readdir(dir);
|
||||
}
|
||||
|
||||
int lastError = errno;
|
||||
if (lastError != 0)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, filter, lastError);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
int lastError = errno;
|
||||
if (lastError != ENOENT)
|
||||
{
|
||||
EBUS_EVENT(FileIOEventBus, OnError, nullptr, filter, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1392,7 +1392,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
// Fixture for thread-driller-bus related calls
|
||||
// Fixture for thread-event-bus related calls
|
||||
// exists only to categorize the tests.
|
||||
class ThreadEventsBus :
|
||||
public AllocatorsFixture
|
||||
@@ -1438,44 +1438,33 @@ namespace UnitTest
|
||||
TEST_F(ThreadEventsBus, Broadcasts_BothBusses)
|
||||
{
|
||||
ThreadEventCounter<AZStd::ThreadEventBus::Handler> eventBusCounter;
|
||||
ThreadEventCounter<AZStd::ThreadDrillerEventBus::Handler> drillerBusCounter;
|
||||
auto thread_function = [&]()
|
||||
{
|
||||
; // intentionally left blank
|
||||
};
|
||||
|
||||
eventBusCounter.Connect();
|
||||
drillerBusCounter.Connect();
|
||||
|
||||
AZStd::thread starter = AZStd::thread(thread_function);
|
||||
starter.join();
|
||||
EXPECT_EQ(drillerBusCounter.m_enterCount, 1);
|
||||
EXPECT_EQ(drillerBusCounter.m_exitCount, 1);
|
||||
EXPECT_EQ(eventBusCounter.m_enterCount, 1);
|
||||
EXPECT_EQ(eventBusCounter.m_exitCount, 1);
|
||||
eventBusCounter.Disconnect();
|
||||
drillerBusCounter.Disconnect();
|
||||
}
|
||||
|
||||
// this class tests for deadlocks caused by interactions between the thread
|
||||
// driller bus and the other driller busses.
|
||||
// Client code (ie, not part of the driller system) can connec to the
|
||||
// ThreadEventBus and be told when threads are started and stopped
|
||||
// However, if they instead listen to the ThreadDrillerEventBus, a deadlock condition
|
||||
// could be caused if they lock a mutex that another thread needs in order to proceed.
|
||||
// This test makes sure that using the ThreadEventBus (ie, the one meant for client code)
|
||||
// instead of the ThreadDrillerEventBus (the one meant only for profilers) does NOT cause
|
||||
// a deadlock.
|
||||
// This class tests for deadlocks caused by multiple threads interacting with the ThreadEventBus.
|
||||
// Client code can connect to the ThreadEventBus and be told when threads are started and stopped.
|
||||
// A deadlock condition could be caused if they lock a mutex that another thread needs in order to proceed.
|
||||
// This test makes sure that using the ThreadEventBus does NOT cause a deadlock.
|
||||
|
||||
// We will simulate this series of events by doing the following
|
||||
// 1. Main thread listens on the ThreadEventBus
|
||||
// 2. OnThreadExit will lock a mutex, perform an allocation, unlock a mutex
|
||||
// 3. The thread itself will lock the mutex, perform an allocation, unlock the mutex.
|
||||
// As long as there is no cross talk between the client and the driller busses, the
|
||||
// above operation should not deadlock.
|
||||
// but if there is, then a deadlock can occur where one thread will be unable to perform
|
||||
// its allocation because the other is in OnThreadExit()
|
||||
// and the other will not be able to perform OnThreadExit() because it cannot lock the mutex.
|
||||
// As long as there is no cross talk between threads, the above operation should not deadlock.
|
||||
// If there is, then a deadlock can occur where one thread will be unable to perform
|
||||
// its allocation because the other is in OnThreadExit() and the other will not be able to perform
|
||||
// OnThreadExit() because it cannot lock the mutex.
|
||||
|
||||
class ThreadEventsDeathTest :
|
||||
public AllocatorsFixture
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "UserTypes.h"
|
||||
#include <AzCore/std/typetraits/internal/is_template_copy_constructible.h>
|
||||
#include <AzCore/std/containers/forward_list.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
|
||||
@@ -175,7 +175,6 @@ namespace UnitTest
|
||||
ComponentApplication componentApp;
|
||||
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 = &AZ::AllocatorInstance<AZ::SystemAllocator>::Get();
|
||||
Entity* systemEntity = componentApp.Create(desc, startupParams);
|
||||
@@ -631,7 +630,6 @@ namespace UnitTest
|
||||
|
||||
ComponentApplication::Descriptor desc;
|
||||
desc.m_useExistingAllocator = true;
|
||||
desc.m_enableDrilling = false; // we already created a memory driller for the test (AllocatorsFixture in Components)
|
||||
|
||||
ComponentApplication::StartupParameters startupParams;
|
||||
startupParams.m_allocator = &AZ::AllocatorInstance<AZ::SystemAllocator>::Get();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
#include <AzCore/Debug/TraceMessagesDrillerBus.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
@@ -104,7 +104,7 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
class TraceTest
|
||||
: public AZ::Debug::TraceMessageDrillerBus::Handler
|
||||
: public AZ::Debug::TraceMessageBus::Handler
|
||||
, public ::testing::Test
|
||||
{
|
||||
int m_numTracePrintfs;
|
||||
@@ -113,12 +113,13 @@ namespace UnitTest
|
||||
: m_numTracePrintfs(0) {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TraceMessagesDrillerBus
|
||||
void OnPrintf(const char* windowName, const char* message) override
|
||||
// TraceMessageBus
|
||||
bool OnPrintf(const char* windowName, const char* message) override
|
||||
{
|
||||
(void)windowName;
|
||||
(void)message;
|
||||
++m_numTracePrintfs;
|
||||
return false;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -1,169 +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/Debug/AssetTrackingTypesImpl.h>
|
||||
#include <AzCore/Debug/AssetTracking.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct TestData
|
||||
{
|
||||
};
|
||||
|
||||
using AssetTree = AZ::Debug::AssetTree<TestData>;
|
||||
using AllocationTable = AZ::Debug::AllocationTable<TestData>;
|
||||
|
||||
struct AssetTrackingTestEnvironment
|
||||
{
|
||||
AssetTrackingTestEnvironment() : m_table(m_mutex)
|
||||
{
|
||||
}
|
||||
|
||||
AZStd::mutex m_mutex;
|
||||
AssetTree m_tree;
|
||||
AllocationTable m_table;
|
||||
AZStd::unique_ptr<AZ::Debug::AssetTracking> m_assetTracking;
|
||||
};
|
||||
}
|
||||
|
||||
class AssetTrackingTests
|
||||
: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::Debug::AssetTrackingAllocator>::Create();
|
||||
m_env.reset(new AssetTrackingTestEnvironment);
|
||||
m_env->m_assetTracking.reset(aznew AZ::Debug::AssetTracking(&m_env->m_tree, &m_env->m_table));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_env.reset();
|
||||
AZ::AllocatorInstance<AZ::Debug::AssetTrackingAllocator>::Destroy();
|
||||
}
|
||||
|
||||
void RunTests()
|
||||
{
|
||||
TestAssetScopes();
|
||||
TestScopedAllocation();
|
||||
TestScopeAttach();
|
||||
}
|
||||
|
||||
private:
|
||||
void TestAssetScopes()
|
||||
{
|
||||
const char* debugScopeText;
|
||||
{
|
||||
AZ_ASSET_NAMED_SCOPE("TestAssetScopes.1");
|
||||
{
|
||||
AZ_ASSET_NAMED_SCOPE("TestAssetScopes.2");
|
||||
{
|
||||
AZ_ASSET_NAMED_SCOPE("TestAssetScopes.3");
|
||||
debugScopeText = AZ::Debug::AssetTracking::GetDebugScope();
|
||||
EXPECT_STREQ(debugScopeText, "TestAssetScopes.3\nTestAssetScopes.2\nTestAssetScopes.1\n");
|
||||
}
|
||||
|
||||
debugScopeText = AZ::Debug::AssetTracking::GetDebugScope();
|
||||
EXPECT_STREQ(debugScopeText, "TestAssetScopes.2\nTestAssetScopes.1\n");
|
||||
}
|
||||
|
||||
|
||||
debugScopeText = AZ::Debug::AssetTracking::GetDebugScope();
|
||||
EXPECT_STREQ(debugScopeText, "TestAssetScopes.1\n");
|
||||
}
|
||||
}
|
||||
|
||||
void TestScopedAllocation()
|
||||
{
|
||||
void* TEST_POINTER = (void*)0xDEADBEEFull;
|
||||
static const size_t TEST_SIZE = 32;
|
||||
|
||||
{
|
||||
AZ_ASSET_NAMED_SCOPE("TestScopedAllocation.1");
|
||||
AZ::Debug::AssetTreeNodeBase* activeAsset = m_env->m_assetTracking->GetCurrentThreadAsset();
|
||||
m_env->m_table.Get().emplace(TEST_POINTER, AllocationTable::RecordType{ activeAsset, (uint32_t)TEST_SIZE, TestData() });
|
||||
}
|
||||
|
||||
auto& rootAsset = m_env->m_tree.m_rootAssets;
|
||||
auto itr = rootAsset.m_children.find("TestScopedAllocation.1");
|
||||
|
||||
EXPECT_EQ(&rootAsset, &m_env->m_tree.GetRoot());
|
||||
ASSERT_NE(itr, rootAsset.m_children.end());
|
||||
EXPECT_EQ(itr->second.m_primaryinfo->m_id->m_id, "TestScopedAllocation.1");
|
||||
|
||||
EXPECT_EQ(&itr->second, m_env->m_table.FindAllocation(TEST_POINTER));
|
||||
|
||||
auto allocationRecord = m_env->m_table.Get().find(TEST_POINTER);
|
||||
ASSERT_NE(allocationRecord, m_env->m_table.Get().end());
|
||||
EXPECT_EQ(allocationRecord->second.m_asset, &itr->second);
|
||||
EXPECT_EQ(allocationRecord->second.m_size, TEST_SIZE);
|
||||
|
||||
// Test realocation
|
||||
void* TEST_REALLOC_POINTER = (void*)0xDEADC0DEull;
|
||||
static const size_t TEST_REALLOC_SIZE = 128;
|
||||
|
||||
m_env->m_table.ReallocateAllocation(TEST_POINTER, TEST_REALLOC_POINTER, TEST_REALLOC_SIZE);
|
||||
allocationRecord = m_env->m_table.Get().find(TEST_POINTER);
|
||||
EXPECT_EQ(allocationRecord, m_env->m_table.Get().end());
|
||||
allocationRecord = m_env->m_table.Get().find(TEST_REALLOC_POINTER);
|
||||
ASSERT_NE(allocationRecord, m_env->m_table.Get().end());
|
||||
EXPECT_EQ(allocationRecord->second.m_asset, &itr->second);
|
||||
EXPECT_EQ(allocationRecord->second.m_size, TEST_REALLOC_SIZE);
|
||||
|
||||
// Test resize
|
||||
static const size_t TEST_RESIZE_SIZE = 1024;
|
||||
m_env->m_table.ResizeAllocation(TEST_REALLOC_POINTER, TEST_RESIZE_SIZE);
|
||||
EXPECT_EQ(allocationRecord->second.m_size, TEST_RESIZE_SIZE);
|
||||
}
|
||||
|
||||
void TestScopeAttach()
|
||||
{
|
||||
void* TEST_POINTER = (void*)0xDEADBEEFull;
|
||||
static const size_t TEST_SIZE = 32;
|
||||
AZ::Debug::AssetTreeNodeBase* originatingAsset;
|
||||
|
||||
{
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(TEST_POINTER);
|
||||
EXPECT_EQ(m_env->m_assetTracking->GetCurrentThreadAsset(), nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
AZ_ASSET_NAMED_SCOPE("TestScopeAttach.1");
|
||||
{
|
||||
AZ_ASSET_NAMED_SCOPE("TestScopeAttach.2");
|
||||
{
|
||||
originatingAsset = m_env->m_assetTracking->GetCurrentThreadAsset();
|
||||
EXPECT_NE(originatingAsset, nullptr);
|
||||
m_env->m_table.Get().emplace(TEST_POINTER, AllocationTable::RecordType{ originatingAsset, (uint32_t)TEST_SIZE, TestData() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(m_env->m_assetTracking->GetCurrentThreadAsset(), nullptr);
|
||||
|
||||
{
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(TEST_POINTER);
|
||||
EXPECT_EQ(m_env->m_assetTracking->GetCurrentThreadAsset(), originatingAsset);
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AssetTrackingTestEnvironment> m_env;
|
||||
};
|
||||
|
||||
TEST_F(AssetTrackingTests, Test)
|
||||
{
|
||||
RunTests();
|
||||
}
|
||||
}
|
||||
@@ -2500,7 +2500,7 @@ namespace UnitTest
|
||||
|
||||
namespace RoutingTest
|
||||
{
|
||||
class DrillerInterceptor : public EBusVersion1::Router
|
||||
class EBusInterceptor : public EBusVersion1::Router
|
||||
{
|
||||
public:
|
||||
void OnEvent(int a) override
|
||||
@@ -2555,20 +2555,20 @@ namespace UnitTest
|
||||
TEST_F(EBus, Routing)
|
||||
{
|
||||
using namespace RoutingTest;
|
||||
DrillerInterceptor driller;
|
||||
EBusInterceptor interceptor;
|
||||
EBusVersion1Handler v1Handler;
|
||||
|
||||
v1Handler.BusConnect();
|
||||
driller.BusRouterConnect();
|
||||
interceptor.BusRouterConnect();
|
||||
|
||||
EBusVersion1::Broadcast(&EBusVersion1::Events::OnEvent, 1020);
|
||||
EXPECT_EQ(1, driller.m_numOnEvent);
|
||||
EXPECT_EQ(1, interceptor.m_numOnEvent);
|
||||
EXPECT_EQ(1, v1Handler.m_numOnEvent);
|
||||
|
||||
driller.BusRouterDisconnect();
|
||||
interceptor.BusRouterDisconnect();
|
||||
|
||||
EBusVersion1::Broadcast(&EBusVersion1::Events::OnEvent, 1020);
|
||||
EXPECT_EQ(1, driller.m_numOnEvent);
|
||||
EXPECT_EQ(1, interceptor.m_numOnEvent);
|
||||
EXPECT_EQ(2, v1Handler.m_numOnEvent);
|
||||
|
||||
// routing events
|
||||
|
||||
@@ -402,17 +402,18 @@ namespace UnitTest
|
||||
AllocatorsFixture::SetUp();
|
||||
AZ::ComponentApplication::Descriptor desc;
|
||||
desc.m_useExistingAllocator = true;
|
||||
desc.m_enableDrilling = false; // we already created a memory driller for the test (AllocatorsFixture)
|
||||
m_app.Create(desc);
|
||||
m_app.reset(aznew AZ::ComponentApplication);
|
||||
m_app->Create(desc);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_app.Destroy();
|
||||
m_app->Destroy();
|
||||
m_app.reset();
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
AZ::ComponentApplication m_app;
|
||||
AZStd::unique_ptr<AZ::ComponentApplication> m_app;
|
||||
};
|
||||
|
||||
TEST_F(MATH_TransformApplicationFixture, DeserializingOldFormat)
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include <AzCore/Memory/HeapSchema.h>
|
||||
#include <AzCore/Memory/HphaSchema.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Memory/MemoryDriller.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
@@ -44,16 +42,13 @@ namespace UnitTest
|
||||
void SetUp() override
|
||||
{
|
||||
AZ::AllocatorManager::Instance().SetDefaultTrackingMode(AZ::Debug::AllocationRecords::RECORD_FULL);
|
||||
m_drillerManager = Debug::DrillerManager::Create();
|
||||
m_drillerManager->Register(aznew MemoryDriller);
|
||||
AZ::AllocatorManager::Instance().EnterProfilingMode();
|
||||
}
|
||||
void TearDown() override
|
||||
{
|
||||
Debug::DrillerManager::Destroy(m_drillerManager);
|
||||
AZ::AllocatorManager::Instance().ExitProfilingMode();
|
||||
AZ::AllocatorManager::Instance().SetDefaultTrackingMode(AZ::Debug::AllocationRecords::RECORD_NO_RECORDS);
|
||||
}
|
||||
protected:
|
||||
Debug::DrillerManager* m_drillerManager = nullptr;
|
||||
};
|
||||
|
||||
class SystemAllocatorTest
|
||||
|
||||
@@ -270,8 +270,7 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
m_drillerManager = AZ::Debug::DrillerManager::Create();
|
||||
m_drillerManager->Register(aznew AZ::Debug::MemoryDriller);
|
||||
AZ::AllocatorManager::Instance().EnterProfilingMode();
|
||||
AZ::AllocatorManager::Instance().SetDefaultTrackingMode(AZ::Debug::AllocationRecords::RECORD_FULL);
|
||||
|
||||
if (azrtti_typeid<AllocatorType>() != azrtti_typeid<AZ::SystemAllocator>()) // simplifies instead of template specialization
|
||||
@@ -292,7 +291,7 @@ namespace UnitTest
|
||||
// Other allocators need the SystemAllocator in order to work
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
AZ::Debug::DrillerManager::Destroy(m_drillerManager);
|
||||
AZ::AllocatorManager::Instance().ExitProfilingMode();
|
||||
|
||||
m_busRedirector.BusDisconnect();
|
||||
EXPECT_EQ(m_leakExpected, m_leakDetected);
|
||||
@@ -352,7 +351,6 @@ namespace UnitTest
|
||||
};
|
||||
|
||||
BusRedirector m_busRedirector;
|
||||
AZ::Debug::DrillerManager* m_drillerManager = nullptr;
|
||||
bool m_leakDetected = false;
|
||||
bool m_leakExpected = false;
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <AzCore/std/containers/fixed_unordered_map.h>
|
||||
#include <AzCore/std/containers/fixed_unordered_set.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/std/containers/forward_list.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/std/containers/list.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/forward_list.h>
|
||||
#include <AzCore/std/iterator.h>
|
||||
#include <Tests/Serialization/Json/JsonSerializerConformityTests.h>
|
||||
#include <Tests/Serialization/Json/TestCases_Classes.h>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#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/Debug/TraceMessageBus.h>
|
||||
|
||||
#include <AzCore/Statistics/StatisticalProfilerProxy.h>
|
||||
|
||||
@@ -468,28 +468,29 @@ namespace UnitTest
|
||||
/** Trace message handler to track messages during tests
|
||||
*/
|
||||
struct MyTraceMessageSink final
|
||||
: public AZ::Debug::TraceMessageDrillerBus::Handler
|
||||
: public AZ::Debug::TraceMessageBus::Handler
|
||||
{
|
||||
MyTraceMessageSink()
|
||||
{
|
||||
AZ::Debug::TraceMessageDrillerBus::Handler::BusConnect();
|
||||
AZ::Debug::TraceMessageBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
~MyTraceMessageSink()
|
||||
{
|
||||
AZ::Debug::TraceMessageDrillerBus::Handler::BusDisconnect();
|
||||
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TraceMessageDrillerBus
|
||||
void OnPrintf(const char* window, const char* message) override
|
||||
// TraceMessageBus
|
||||
bool OnPrintf(const char* window, const char* message) override
|
||||
{
|
||||
OnOutput(window, message);
|
||||
return OnOutput(window, message);
|
||||
}
|
||||
|
||||
void OnOutput(const char* window, const char* message) override
|
||||
bool OnOutput(const char* window, const char* message) override
|
||||
{
|
||||
printf("%s: %s\n", window, message);
|
||||
return false;
|
||||
}
|
||||
}; //struct MyTraceMessageSink
|
||||
|
||||
|
||||
@@ -258,7 +258,6 @@ namespace AZ
|
||||
m_application = aznew GemTestApplication();
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_useExistingAllocator = true;
|
||||
appDesc.m_enableDrilling = false;
|
||||
auto m_systemEntity = m_application->Create(appDesc);
|
||||
m_systemEntity->AddComponent(aznew AZ::StreamerComponent());
|
||||
m_systemEntity->Init();
|
||||
|
||||
@@ -69,7 +69,6 @@ set(FILES
|
||||
TickBusTest.cpp
|
||||
UUIDTests.cpp
|
||||
XML.cpp
|
||||
Debug/AssetTracking.cpp
|
||||
Debug/LocalFileEventLoggerTests.cpp
|
||||
Debug/Trace.cpp
|
||||
Debug/UnhandledExceptions.cpp
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <AzFramework/Asset/AssetSystemComponent.h>
|
||||
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
@@ -17,7 +18,6 @@
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <AzFramework/Asset/Benchmark/BenchmarkCommands.h>
|
||||
#include <AzFramework/Network/AssetProcessorConnection.h>
|
||||
|
||||
AZ_DECLARE_BUDGET(AzFramework);
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
namespace AssetBenchmark
|
||||
@@ -302,7 +304,7 @@ namespace AzFramework
|
||||
// SystemTickBus overrides
|
||||
void AssetSystemComponent::OnSystemTick()
|
||||
{
|
||||
AZ_TRACE_METHOD();
|
||||
AZ_PROFILE_FUNCTION(AzFramework);
|
||||
LegacyAssetEventBus::ExecuteQueuedEvents();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Debug/AssetTracking.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Component/EntityUtils.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
@@ -243,8 +242,6 @@ namespace AzFramework
|
||||
//=========================================================================
|
||||
void EntityContext::ActivateEntity(AZ::EntityId entityId)
|
||||
{
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(this);
|
||||
|
||||
// Verify that this context has the right to perform operations on the entity
|
||||
bool validEntity = IsOwnedByThisContext(entityId);
|
||||
AZ_Warning("GameEntityContext", validEntity, "Entity with id %llu does not belong to the game context.", entityId);
|
||||
|
||||
@@ -386,7 +386,6 @@ namespace AzFramework
|
||||
void SliceEntityOwnershipService::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> readyAsset)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzFramework);
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(readyAsset.Get());
|
||||
|
||||
AZ_Assert(readyAsset.GetAs<AZ::SliceAsset>(), "Asset is not a slice!");
|
||||
|
||||
@@ -400,7 +399,6 @@ namespace AzFramework
|
||||
// we intentionally capture readyAsset by value here, so that its refcount doesn't hit 0 by the time this call happens.
|
||||
AZStd::function<void()> instantiateCallback = [this, readyAsset]()
|
||||
{
|
||||
AZ_ASSET_ATTACH_TO_SCOPE(readyAsset.Get());
|
||||
const AZ::Data::AssetId readyAssetId = readyAsset.GetId();
|
||||
for (auto iter = m_queuedSliceInstantiations.begin(); iter != m_queuedSliceInstantiations.end(); )
|
||||
{
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
#include <AzFramework/XcbInterface.h>
|
||||
|
||||
@@ -34,24 +34,20 @@ namespace UnitTest
|
||||
AllocatorInstance<ThreadPoolAllocator>::Create();
|
||||
ComponentApplication::Descriptor desc;
|
||||
desc.m_useExistingAllocator = true;
|
||||
desc.m_enableDrilling = false; // we already created a memory driller for the test (AllocatorsFixture)
|
||||
m_app.Create(desc);
|
||||
m_app.reset(aznew ComponentApplication);
|
||||
m_app->Create(desc);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_app.Destroy();
|
||||
m_app->Destroy();
|
||||
m_app.reset();
|
||||
AllocatorInstance<PoolAllocator>::Destroy();
|
||||
AllocatorInstance<ThreadPoolAllocator>::Destroy();
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
~Base64Test() override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ComponentApplication m_app;
|
||||
AZStd::unique_ptr<ComponentApplication> m_app;
|
||||
};
|
||||
|
||||
TEST_F(Base64Test, EmptyStringEncodeTest)
|
||||
|
||||
@@ -58,7 +58,6 @@ namespace UnitTest
|
||||
ComponentApplication app;
|
||||
ComponentApplication::Descriptor desc;
|
||||
desc.m_useExistingAllocator = true;
|
||||
desc.m_enableDrilling = false; // we already created a memory driller for the test (AllocatorsFixture)
|
||||
app.Create(desc);
|
||||
|
||||
Data::AssetManager::Instance().RegisterHandler(aznew SliceAssetHandler(app.GetSerializeContext()), AZ::AzTypeInfo<AZ::SliceAsset>::Uuid());
|
||||
|
||||
@@ -83,7 +83,6 @@ namespace UnitTest
|
||||
m_data = AZStd::make_unique<StaticData>();
|
||||
using namespace AzFramework::FileTag;
|
||||
AZ::ComponentApplication::Descriptor desc;
|
||||
desc.m_enableDrilling = false;
|
||||
m_data->m_application.Start(desc);
|
||||
|
||||
const char* testAssetRoot = m_tempDirectory.GetDirectory();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
#include "MockXcbInterface.h"
|
||||
|
||||
@@ -17,7 +18,7 @@ namespace AzFramework
|
||||
{
|
||||
// Sets up mock behavior for the xcb library, providing an xcb_connection_t that is returned from a call to xcb_connect
|
||||
class XcbBaseTestFixture
|
||||
: public testing::Test
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override;
|
||||
|
||||
@@ -113,7 +113,6 @@ namespace SceneUnitTest
|
||||
m_app.RegisterComponentDescriptor(AZ::StreamerComponent::CreateDescriptor());
|
||||
|
||||
AZ::ComponentApplication::Descriptor desc;
|
||||
desc.m_enableDrilling = false; // the unit test framework already adds a driller
|
||||
m_systemEntity = m_app.Create(desc);
|
||||
m_systemEntity->Init();
|
||||
|
||||
|
||||
@@ -91,7 +91,6 @@ namespace AZ
|
||||
m_application = CreateApplicationInstance();
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_useExistingAllocator = true;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
// Set up gems for loading.
|
||||
for (const AZStd::string& dynamicModulePath : m_parameters->m_dynamicModulePaths)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user