Merge branch 'development' into 3495_preferences_panel_update
This commit is contained in:
@@ -26,7 +26,6 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Plane Plane::CreateFromNormalAndDistance(const Vector3& normal, float dist)
|
||||
{
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
|
||||
Plane result;
|
||||
result.Set(normal, dist);
|
||||
return result;
|
||||
@@ -35,7 +34,6 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Plane Plane::CreateFromCoefficients(const float a, const float b, const float c, const float d)
|
||||
{
|
||||
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
|
||||
Plane result;
|
||||
result.Set(a, b, c, d);
|
||||
return result;
|
||||
@@ -68,21 +66,21 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE void Plane::Set(const Vector3& normal, float d)
|
||||
{
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
|
||||
m_plane.Set(normal, d);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Plane::Set(float a, float b, float c, float d)
|
||||
{
|
||||
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
|
||||
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is not normalized");
|
||||
m_plane.Set(a, b, c, d);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Plane::SetNormal(const Vector3& normal)
|
||||
{
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
|
||||
m_plane.SetX(normal.GetX());
|
||||
m_plane.SetY(normal.GetY());
|
||||
m_plane.SetZ(normal.GetZ());
|
||||
|
||||
@@ -6,8 +6,155 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
|
||||
#define RECORDING_ENABLED 0
|
||||
|
||||
#if RECORDING_ENABLED
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
class DebugAllocator
|
||||
{
|
||||
public:
|
||||
using pointer_type = void*;
|
||||
using size_type = AZStd::size_t;
|
||||
using difference_type = AZStd::ptrdiff_t;
|
||||
using allow_memory_leaks = AZStd::false_type; ///< Regular allocators should not leak.
|
||||
|
||||
AZ_FORCE_INLINE pointer_type allocate(size_t byteSize, size_t alignment, int = 0)
|
||||
{
|
||||
return AZ_OS_MALLOC(byteSize, alignment);
|
||||
}
|
||||
AZ_FORCE_INLINE size_type resize(pointer_type, size_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
AZ_FORCE_INLINE void deallocate(pointer_type ptr, size_type, size_type)
|
||||
{
|
||||
AZ_OS_FREE(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct alignas(1) AllocatorOperation
|
||||
{
|
||||
enum OperationType : size_t
|
||||
{
|
||||
ALLOCATE,
|
||||
DEALLOCATE
|
||||
};
|
||||
OperationType m_type: 1;
|
||||
size_t m_size : 28; // Can represent up to 256Mb requests
|
||||
size_t m_alignment : 7; // Can represent up to 128 alignment
|
||||
size_t m_recordId : 28; // Can represent up to 256M simultaneous requests, we reuse ids
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(AllocatorOperation) == 8);
|
||||
|
||||
static AZStd::mutex s_operationsMutex = {};
|
||||
|
||||
static constexpr size_t s_maxNumberOfAllocationsToRecord = 16384;
|
||||
static size_t s_numberOfAllocationsRecorded = 0;
|
||||
static constexpr size_t s_allocationOperationCount = 5 * 1024;
|
||||
static AZStd::array<AllocatorOperation, s_allocationOperationCount> s_operations = {};
|
||||
static uint64_t s_operationCounter = 0;
|
||||
|
||||
static unsigned int s_nextRecordId = 1;
|
||||
using AllocatorOperationByAddress = AZStd::unordered_map<void*, AllocatorOperation, AZStd::less<void*>, DebugAllocator>;
|
||||
static AllocatorOperationByAddress s_allocatorOperationByAddress;
|
||||
using AvailableRecordIds = AZStd::vector<unsigned int, DebugAllocator>;
|
||||
AvailableRecordIds s_availableRecordIds;
|
||||
|
||||
void RecordAllocatorOperation(AllocatorOperation::OperationType type, void* ptr, size_t size = 0, size_t alignment = 0)
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::mutex> lock(s_operationsMutex);
|
||||
if (s_operationCounter == s_allocationOperationCount)
|
||||
{
|
||||
AZ::IO::SystemFile file;
|
||||
int mode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND | AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY;
|
||||
if (!file.Exists("memoryrecordings.bin"))
|
||||
{
|
||||
mode |= AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE;
|
||||
}
|
||||
file.Open("memoryrecordings.bin", mode);
|
||||
if (file.IsOpen())
|
||||
{
|
||||
file.Write(&s_operations, sizeof(AllocatorOperation) * s_allocationOperationCount);
|
||||
file.Close();
|
||||
}
|
||||
s_operationCounter = 0;
|
||||
}
|
||||
AllocatorOperation& operation = s_operations[s_operationCounter++];
|
||||
operation.m_type = type;
|
||||
if (type == AllocatorOperation::OperationType::ALLOCATE)
|
||||
{
|
||||
if (s_numberOfAllocationsRecorded > s_maxNumberOfAllocationsToRecord)
|
||||
{
|
||||
// reached limit of allocations, dont record anymore
|
||||
--s_operationCounter;
|
||||
return;
|
||||
}
|
||||
++s_numberOfAllocationsRecorded;
|
||||
operation.m_size = size;
|
||||
operation.m_alignment = alignment;
|
||||
unsigned int recordId = 0;
|
||||
if (!s_availableRecordIds.empty())
|
||||
{
|
||||
recordId = s_availableRecordIds.back();
|
||||
s_availableRecordIds.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
recordId = s_nextRecordId;
|
||||
++s_nextRecordId;
|
||||
}
|
||||
operation.m_recordId = recordId;
|
||||
auto it = s_allocatorOperationByAddress.emplace(ptr, operation);
|
||||
if (!it.second)
|
||||
{
|
||||
// double alloc or resize, leave the current record and return the id
|
||||
operation = it.first->second;
|
||||
s_availableRecordIds.emplace_back(recordId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
// common scenario, just record the operation
|
||||
operation.m_size = 0;
|
||||
operation.m_alignment = 0;
|
||||
operation.m_recordId = 0; // recordId = 0 will flag this case
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = s_allocatorOperationByAddress.find(ptr);
|
||||
if (it != s_allocatorOperationByAddress.end())
|
||||
{
|
||||
operation.m_size = it->second.m_size;
|
||||
operation.m_alignment = it->second.m_alignment;
|
||||
operation.m_recordId = it->second.m_recordId;
|
||||
s_availableRecordIds.push_back(it->second.m_recordId);
|
||||
s_allocatorOperationByAddress.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
// just dont record this operation
|
||||
--s_operationCounter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -150,6 +297,10 @@ namespace AZ
|
||||
records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#if RECORDING_ENABLED
|
||||
RecordAllocatorOperation(AllocatorOperation::ALLOCATE, ptr, byteSize, alignment);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t alignment, Debug::AllocationInfo* info)
|
||||
@@ -162,6 +313,9 @@ namespace AZ
|
||||
records->UnregisterAllocation(ptr, byteSize, alignment, info);
|
||||
}
|
||||
}
|
||||
#if RECORDING_ENABLED
|
||||
RecordAllocatorOperation(AllocatorOperation::DEALLOCATE, ptr, byteSize, alignment);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
|
||||
@@ -176,6 +330,10 @@ namespace AZ
|
||||
ProfileDeallocation(ptr, 0, 0, &info);
|
||||
ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
|
||||
}
|
||||
#if RECORDING_ENABLED
|
||||
RecordAllocatorOperation(AllocatorOperation::DEALLOCATE, ptr);
|
||||
RecordAllocatorOperation(AllocatorOperation::ALLOCATE, newPtr, newSize, newAlignment);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocation(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
@@ -193,6 +351,9 @@ namespace AZ
|
||||
records->ResizeAllocation(ptr, newSize);
|
||||
}
|
||||
}
|
||||
#if RECORDING_ENABLED
|
||||
RecordAllocatorOperation(AllocatorOperation::ALLOCATE, ptr, newSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AllocatorBase::OnOutOfMemory(size_t byteSize, size_t alignment, int flags, const char* name, const char* fileName, int lineNum)
|
||||
|
||||
@@ -115,6 +115,7 @@ namespace AZ
|
||||
m_ownMemoryBlock[i] = false;
|
||||
}
|
||||
|
||||
AZ_Assert(m_desc.m_numMemoryBlocks > 0, "At least one memory block is required");
|
||||
for (int i = 0; i < m_desc.m_numMemoryBlocks; ++i)
|
||||
{
|
||||
if (m_desc.m_memoryBlocks[i] == nullptr) // Allocate memory block if requested!
|
||||
@@ -131,17 +132,6 @@ namespace AZ
|
||||
|
||||
m_capacity += m_desc.m_memoryBlocksByteSize[i];
|
||||
}
|
||||
|
||||
if (m_desc.m_numMemoryBlocks == 0)
|
||||
{
|
||||
// Create default memory space if we can to serve for default allocations
|
||||
m_memSpaces[0] = AZDLMalloc::create_mspace(0, m_desc.m_isMultithreadAlloc);
|
||||
if (m_memSpaces[0])
|
||||
{
|
||||
AZDLMalloc::mspace_az_set_expandable(m_memSpaces[0], true);
|
||||
m_capacity = Platform::GetHeapCapacity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeapSchema::~HeapSchema()
|
||||
|
||||
@@ -32,17 +32,11 @@ namespace AZ
|
||||
*/
|
||||
struct Descriptor
|
||||
{
|
||||
Descriptor()
|
||||
: m_numMemoryBlocks(0)
|
||||
, m_isMultithreadAlloc(true)
|
||||
{}
|
||||
|
||||
static const int m_memoryBlockAlignment = 64 * 1024;
|
||||
static const int m_maxNumBlocks = 5;
|
||||
int m_numMemoryBlocks; ///< Number of memory blocks to use.
|
||||
void* m_memoryBlocks[m_maxNumBlocks]; ///< Pointers to provided memory blocks or NULL if you want the system to allocate them for you with the System Allocator.
|
||||
size_t m_memoryBlocksByteSize[m_maxNumBlocks]; ///< Sizes of different memory blocks, if m_memoryBlock is 0 the block will be allocated for you with the System Allocator.
|
||||
bool m_isMultithreadAlloc; ///< Set to true to enable multi threading safe allocation.
|
||||
int m_numMemoryBlocks = 1; ///< Number of memory blocks to use.
|
||||
void* m_memoryBlocks[m_maxNumBlocks] = {}; ///< Pointers to provided memory blocks or NULL if you want the system to allocate them for you with the System Allocator.
|
||||
size_t m_memoryBlocksByteSize[m_maxNumBlocks] = {4 * 1024}; ///< Sizes of different memory blocks, if m_memoryBlock is 0 the block will be allocated for you with the System Allocator.
|
||||
bool m_isMultithreadAlloc = true; ///< Set to true to enable multi threading safe allocation.
|
||||
};
|
||||
|
||||
HeapSchema(const Descriptor& desc);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#define AZCORE_SYSTEM_ALLOCATOR_HPHA 1
|
||||
#define AZCORE_SYSTEM_ALLOCATOR_MALLOC 2
|
||||
#define AZCORE_SYSTEM_ALLOCATOR_HEAP 3
|
||||
|
||||
#if !defined(AZCORE_SYSTEM_ALLOCATOR)
|
||||
// define the default
|
||||
@@ -29,8 +28,6 @@
|
||||
#include <AzCore/Memory/HphaSchema.h>
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
#include <AzCore/Memory/MallocSchema.h>
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
#include <AzCore/Memory/HeapSchema.h>
|
||||
#else
|
||||
#error "Invalid allocator selected for SystemAllocator"
|
||||
#endif
|
||||
@@ -44,8 +41,6 @@ namespace AZ
|
||||
static AZStd::aligned_storage<sizeof(HphaSchema), AZStd::alignment_of<HphaSchema>::value>::type g_systemSchema;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
static AZStd::aligned_storage<sizeof(MallocSchema), AZStd::alignment_of<MallocSchema>::value>::type g_systemSchema;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
static AZStd::aligned_storage<sizeof(HeapSchema), AZStd::alignment_of<HeapSchema>::value>::type g_systemSchema;
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -118,11 +113,6 @@ namespace AZ
|
||||
heapDesc.m_systemChunkSize = desc.m_heap.m_systemChunkSize;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
MallocSchema::Descriptor heapDesc;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
HeapSchema::Descriptor heapDesc;
|
||||
memcpy(heapDesc.m_memoryBlocks, desc.m_heap.m_memoryBlocks, sizeof(heapDesc.m_memoryBlocks));
|
||||
memcpy(heapDesc.m_memoryBlocksByteSize, desc.m_heap.m_memoryBlocksByteSize, sizeof(heapDesc.m_memoryBlocksByteSize));
|
||||
heapDesc.m_numMemoryBlocks = desc.m_heap.m_numMemoryBlocks;
|
||||
#endif
|
||||
if (&AllocatorInstance<SystemAllocator>::Get() == this) // if we are the system allocator
|
||||
{
|
||||
@@ -132,8 +122,6 @@ namespace AZ
|
||||
m_allocator = new (&g_systemSchema) HphaSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = new (&g_systemSchema) MallocSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = new (&g_systemSchema) HeapSchema(heapDesc);
|
||||
#endif
|
||||
g_isSystemSchemaUsed = true;
|
||||
isReady = true;
|
||||
@@ -149,8 +137,6 @@ namespace AZ
|
||||
m_allocator = azcreate(HphaSchema, (heapDesc), SystemAllocator);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = azcreate(MallocSchema, (heapDesc), SystemAllocator);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = azcreate(HeapSchema, (heapDesc), SystemAllocator);
|
||||
#endif
|
||||
if (m_allocator == nullptr)
|
||||
{
|
||||
@@ -186,8 +172,6 @@ namespace AZ
|
||||
static_cast<HphaSchema*>(m_allocator)->~HphaSchema();
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
static_cast<MallocSchema*>(m_allocator)->~MallocSchema();
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
static_cast<HeapSchema*>(m_allocator)->~HeapSchema();
|
||||
#endif
|
||||
g_isSystemSchemaUsed = false;
|
||||
}
|
||||
|
||||
@@ -45,9 +45,8 @@ namespace AZ
|
||||
}
|
||||
else
|
||||
{
|
||||
SerializerMap::const_iterator serializerIter = m_jsonSerializers.find(typeId);
|
||||
AZ_Assert(serializerIter != m_jsonSerializers.end(), "Attempting to unregister a serializer that has not been registered yet with typeid %s", typeId.ToString<AZStd::string>().c_str());
|
||||
m_jsonSerializers.erase(serializerIter);
|
||||
[[maybe_unused]] size_t erased = m_jsonSerializers.erase(typeId);
|
||||
AZ_Assert(erased == 1, "Attempting to unregister a serializer that has not been registered yet with typeid %s", typeId.ToString<AZStd::string>().c_str());
|
||||
return SerializerBuilder(this, m_jsonSerializers.end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,11 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
VALUES AZCORETEST_DLL_NAME=\"$<TARGET_FILE_NAME:AzCore.Tests>\"
|
||||
)
|
||||
ly_add_target_files(
|
||||
TARGETS AzCore.Tests
|
||||
FILES ${CMAKE_CURRENT_SOURCE_DIR}/Tests/Memory/AllocatorBenchmarkRecordings.bin
|
||||
OUTPUT_SUBDIRECTORY Tests/AzCore/Memory
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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/UnitTest/TestTypes.h>
|
||||
|
||||
#if AZ_DEBUG_BUILD
|
||||
#define AZ_MATH_TEST_START_TRACE_SUPPRESSION AZ_TEST_START_TRACE_SUPPRESSION
|
||||
#define AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(x) AZ_TEST_STOP_TRACE_SUPPRESSION(x)
|
||||
#else
|
||||
#define AZ_MATH_TEST_START_TRACE_SUPPRESSION
|
||||
#define AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(x)
|
||||
#endif
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Vector4.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <Math/MathTest.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
@@ -47,7 +48,9 @@ namespace UnitTest
|
||||
TEST(MATH_Plane, TestSet)
|
||||
{
|
||||
Plane pl;
|
||||
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
|
||||
pl.Set(12.0f, 13.0f, 14.0f, 15.0f);
|
||||
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetDistance(), 15.0f);
|
||||
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetX(), 12.0f);
|
||||
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetY(), 13.0f);
|
||||
@@ -57,7 +60,9 @@ namespace UnitTest
|
||||
TEST(MATH_Plane, TestSetVector3)
|
||||
{
|
||||
Plane pl;
|
||||
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
|
||||
pl.Set(Vector3(22.0f, 23.0f, 24.0f), 25.0f);
|
||||
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetDistance(), 25.0f);
|
||||
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetX(), 22.0f);
|
||||
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetY(), 23.0f);
|
||||
@@ -177,17 +182,21 @@ namespace UnitTest
|
||||
pl.Set(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
AZ_TEST_ASSERT(pl.IsFinite());
|
||||
const float infinity = std::numeric_limits<float>::infinity();
|
||||
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
|
||||
pl.Set(infinity, infinity, infinity, infinity);
|
||||
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
AZ_TEST_ASSERT(!pl.IsFinite());
|
||||
}
|
||||
|
||||
TEST(MATH_Plane, CreateFromVectorCoefficients_IsEquivalentToCreateFromCoefficients)
|
||||
{
|
||||
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
|
||||
Plane planeFromCoefficients = Plane::CreateFromCoefficients(1.0, 2.0, 3.0, 4.0);
|
||||
|
||||
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
Vector4 coefficients(1.0, 2.0, 3.0, 4.0);
|
||||
Plane planeFromVectorCoefficients = Plane::CreateFromVectorCoefficients(coefficients);
|
||||
|
||||
|
||||
EXPECT_EQ(planeFromVectorCoefficients, planeFromCoefficients);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:281ba03e79ecba90b313a0b17bdba87c57d76b504b6e38d579b5eabd995902cc
|
||||
size 245760
|
||||
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_BENCHMARK)
|
||||
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/Memory/BestFitExternalMapAllocator.h>
|
||||
#include <AzCore/Memory/HeapSchema.h>
|
||||
#include <AzCore/Memory/HphaSchema.h>
|
||||
#include <AzCore/Memory/MallocSchema.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Memory/PoolSchema.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
namespace Benchmark
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
size_t GetProcessMemoryUsageBytes();
|
||||
size_t GetMemorySize(void* memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test allocator wrapper that redirects the calls to the passed TAllocator by using AZ::AllocatorInstance.
|
||||
/// It also creates/destroys the TAllocator type (to reflect what happens at runtime)
|
||||
/// </summary>
|
||||
/// <typeparam name="TAllocator">Allocator type to wrap</typeparam>
|
||||
template<typename TAllocator>
|
||||
class TestAllocatorWrapper
|
||||
{
|
||||
public:
|
||||
static void SetUp()
|
||||
{
|
||||
AZ::AllocatorInstance<TAllocator>::Create();
|
||||
}
|
||||
|
||||
static void TearDown()
|
||||
{
|
||||
AZ::AllocatorInstance<TAllocator>::Destroy();
|
||||
}
|
||||
|
||||
static void* Allocate(size_t byteSize, size_t alignment)
|
||||
{
|
||||
return AZ::AllocatorInstance<TAllocator>::Get().Allocate(byteSize, alignment);
|
||||
}
|
||||
|
||||
static void DeAllocate(void* ptr, size_t byteSize = 0)
|
||||
{
|
||||
AZ::AllocatorInstance<TAllocator>::Get().DeAllocate(ptr, byteSize);
|
||||
}
|
||||
|
||||
static void* ReAllocate(void* ptr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
return AZ::AllocatorInstance<TAllocator>::Get().ReAllocate(ptr, newSize, newAlignment);
|
||||
}
|
||||
|
||||
static size_t Resize(void* ptr, size_t newSize)
|
||||
{
|
||||
return AZ::AllocatorInstance<TAllocator>::Get().Resize(ptr, newSize);
|
||||
}
|
||||
|
||||
static void GarbageCollect()
|
||||
{
|
||||
AZ::AllocatorInstance<TAllocator>::Get().GarbageCollect();
|
||||
}
|
||||
|
||||
static size_t NumAllocatedBytes()
|
||||
{
|
||||
return AZ::AllocatorInstance<TAllocator>::Get().NumAllocatedBytes() +
|
||||
AZ::AllocatorInstance<TAllocator>::Get().GetUnAllocatedMemory();
|
||||
}
|
||||
|
||||
static size_t GetSize(void* ptr)
|
||||
{
|
||||
return AZ::AllocatorInstance<TAllocator>::Get().AllocationSize(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Basic allocator used as a baseline. This allocator is the most basic allocation possible with the OS (AZ_OS_MALLOC).
|
||||
/// MallocSchema cannot be used here because it has extra logic that we don't want to use as a baseline.
|
||||
/// </summary>
|
||||
class RawMallocAllocator {};
|
||||
|
||||
template<>
|
||||
class TestAllocatorWrapper<RawMallocAllocator>
|
||||
{
|
||||
public:
|
||||
TestAllocatorWrapper()
|
||||
{
|
||||
s_numAllocatedBytes = 0;
|
||||
}
|
||||
|
||||
static void SetUp()
|
||||
{
|
||||
s_numAllocatedBytes = 0;
|
||||
}
|
||||
|
||||
static void TearDown()
|
||||
{
|
||||
}
|
||||
|
||||
// IAllocatorAllocate
|
||||
static void* Allocate(size_t byteSize, size_t)
|
||||
{
|
||||
s_numAllocatedBytes += byteSize;
|
||||
// Don't pass an alignment since we wont be able to get the memory size without also passing the alignment
|
||||
return AZ_OS_MALLOC(byteSize, 1);
|
||||
}
|
||||
|
||||
static void DeAllocate(void* ptr, size_t = 0)
|
||||
{
|
||||
s_numAllocatedBytes -= Platform::GetMemorySize(ptr);
|
||||
AZ_OS_FREE(ptr);
|
||||
}
|
||||
|
||||
static void* ReAllocate(void* ptr, size_t newSize, size_t)
|
||||
{
|
||||
s_numAllocatedBytes -= Platform::GetMemorySize(ptr);
|
||||
AZ_OS_FREE(ptr);
|
||||
|
||||
s_numAllocatedBytes += newSize;
|
||||
return AZ_OS_MALLOC(newSize, 1);
|
||||
}
|
||||
|
||||
static size_t Resize(void* ptr, size_t newSize)
|
||||
{
|
||||
AZ_UNUSED(ptr);
|
||||
AZ_UNUSED(newSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void GarbageCollect() {}
|
||||
|
||||
static size_t NumAllocatedBytes()
|
||||
{
|
||||
return s_numAllocatedBytes;
|
||||
}
|
||||
|
||||
static size_t GetSize(void* ptr)
|
||||
{
|
||||
return Platform::GetMemorySize(ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t s_numAllocatedBytes;
|
||||
};
|
||||
|
||||
size_t TestAllocatorWrapper<RawMallocAllocator>::s_numAllocatedBytes = 0;
|
||||
|
||||
// Some allocator are not fully declared, those we simply setup from the schema
|
||||
class MallocSchemaAllocator : public AZ::SimpleSchemaAllocator<AZ::MallocSchema>
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(MallocSchemaAllocator, "{3E68224F-E676-402C-8276-CE4B49C05E89}");
|
||||
|
||||
MallocSchemaAllocator()
|
||||
: AZ::SimpleSchemaAllocator<AZ::MallocSchema>("MallocSchemaAllocator", "")
|
||||
{}
|
||||
};
|
||||
|
||||
// We use both this HphaSchemaAllocator and the SystemAllocator configured with Hpha because the SystemAllocator
|
||||
// has extra things
|
||||
class HphaSchemaAllocator : public AZ::SimpleSchemaAllocator<AZ::HphaSchema>
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(HphaSchemaAllocator, "{6563AB4B-A68E-4499-8C98-D61D640D1F7F}");
|
||||
|
||||
HphaSchemaAllocator()
|
||||
: AZ::SimpleSchemaAllocator<AZ::HphaSchema>("TestHphaSchemaAllocator", "")
|
||||
{}
|
||||
};
|
||||
|
||||
// For the SystemAllocator we inherit so we have a different stack. The SystemAllocator is used globally so we dont want
|
||||
// to get that data affecting the benchmark
|
||||
class TestSystemAllocator : public AZ::SystemAllocator
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(TestSystemAllocator, "{360D4DAA-D65D-4D5C-A6FA-1A4C5261C35C}");
|
||||
|
||||
TestSystemAllocator()
|
||||
: AZ::SystemAllocator()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Allocated bytes reported by the allocator
|
||||
static const char* s_counterAllocatorMemory = "Allocator_Memory";
|
||||
|
||||
// Allocated bytes as counted by the benchmark
|
||||
static const char* s_counterBenchmarkMemory = "Benchmark_Memory";
|
||||
|
||||
enum AllocationSize
|
||||
{
|
||||
SMALL,
|
||||
BIG,
|
||||
MIXED,
|
||||
COUNT
|
||||
};
|
||||
|
||||
static const size_t s_kiloByte = 1024;
|
||||
static const size_t s_megaByte = s_kiloByte * s_kiloByte;
|
||||
using AllocationSizeArray = AZStd::array<size_t, 10>;
|
||||
static const AZStd::array<AllocationSizeArray, COUNT> s_allocationSizes = {
|
||||
/* SMALL */ AllocationSizeArray{ 2, 16, 20, 59, 100, 128, 160, 250, 300, 512 },
|
||||
/* BIG */ AllocationSizeArray{ 513, s_kiloByte, 2 * s_kiloByte, 4 * s_kiloByte, 10 * s_kiloByte, 64 * s_kiloByte, 128 * s_kiloByte, 200 * s_kiloByte, s_megaByte, 2 * s_megaByte },
|
||||
/* MIXED */ AllocationSizeArray{ 2, s_kiloByte, 59, 4 * s_kiloByte, 128, 200 * s_kiloByte, 250, s_megaByte, 512, 2 * s_megaByte }
|
||||
};
|
||||
|
||||
template <typename TAllocator>
|
||||
class AllocatorBenchmarkFixture
|
||||
: public ::benchmark::Fixture
|
||||
{
|
||||
protected:
|
||||
using TestAllocatorType = TestAllocatorWrapper<TAllocator>;
|
||||
|
||||
virtual void internalSetUp(const ::benchmark::State& state)
|
||||
{
|
||||
if (state.thread_index == 0) // Only setup in the first thread
|
||||
{
|
||||
TestAllocatorType::SetUp();
|
||||
|
||||
m_allocations.resize(state.threads);
|
||||
for (auto& perThreadAllocations : m_allocations)
|
||||
{
|
||||
perThreadAllocations.resize(state.range(0), nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void internalTearDown(const ::benchmark::State& state)
|
||||
{
|
||||
if (state.thread_index == 0) // Only setup in the first thread
|
||||
{
|
||||
m_allocations.clear();
|
||||
m_allocations.shrink_to_fit();
|
||||
|
||||
TestAllocatorType::TearDown();
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::vector<void*>& GetPerThreadAllocations(size_t threadIndex)
|
||||
{
|
||||
return m_allocations[threadIndex];
|
||||
}
|
||||
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state) override
|
||||
{
|
||||
internalSetUp(state);
|
||||
}
|
||||
void SetUp(::benchmark::State& state) override
|
||||
{
|
||||
internalSetUp(state);
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state) override
|
||||
{
|
||||
internalTearDown(state);
|
||||
}
|
||||
void TearDown(::benchmark::State& state) override
|
||||
{
|
||||
internalTearDown(state);
|
||||
}
|
||||
|
||||
private:
|
||||
AZStd::vector<AZStd::vector<void*>> m_allocations;
|
||||
};
|
||||
|
||||
template <typename TAllocator, AllocationSize TAllocationSize>
|
||||
class AllocationBenchmarkFixture
|
||||
: public AllocatorBenchmarkFixture<TAllocator>
|
||||
{
|
||||
using base = AllocatorBenchmarkFixture<TAllocator>;
|
||||
using TestAllocatorType = typename base::TestAllocatorType;
|
||||
|
||||
public:
|
||||
void Benchmark(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state)
|
||||
{
|
||||
state.PauseTiming();
|
||||
|
||||
AZStd::vector<void*>& perThreadAllocations = base::GetPerThreadAllocations(state.thread_index);
|
||||
const size_t numberOfAllocations = perThreadAllocations.size();
|
||||
size_t totalAllocationSize = 0;
|
||||
for (size_t allocationIndex = 0; allocationIndex < numberOfAllocations; ++allocationIndex)
|
||||
{
|
||||
const AllocationSizeArray& allocationArray = s_allocationSizes[TAllocationSize];
|
||||
const size_t allocationSize = allocationArray[allocationIndex % allocationArray.size()];
|
||||
totalAllocationSize += allocationSize;
|
||||
|
||||
state.ResumeTiming();
|
||||
perThreadAllocations[allocationIndex] = TestAllocatorType::Allocate(allocationSize, 0);
|
||||
state.PauseTiming();
|
||||
}
|
||||
|
||||
state.counters[s_counterAllocatorMemory] = benchmark::Counter(static_cast<double>(TestAllocatorType::NumAllocatedBytes()), benchmark::Counter::kDefaults);
|
||||
state.counters[s_counterBenchmarkMemory] = benchmark::Counter(static_cast<double>(totalAllocationSize), benchmark::Counter::kDefaults);
|
||||
|
||||
for (size_t allocationIndex = 0; allocationIndex < numberOfAllocations; ++allocationIndex)
|
||||
{
|
||||
const AllocationSizeArray& allocationArray = s_allocationSizes[TAllocationSize];
|
||||
const size_t allocationSize = allocationArray[allocationIndex % allocationArray.size()];
|
||||
TestAllocatorType::DeAllocate(perThreadAllocations[allocationIndex], allocationSize);
|
||||
perThreadAllocations[allocationIndex] = nullptr;
|
||||
}
|
||||
TestAllocatorType::GarbageCollect();
|
||||
|
||||
state.SetItemsProcessed(numberOfAllocations);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TAllocator, AllocationSize TAllocationSize>
|
||||
class DeAllocationBenchmarkFixture
|
||||
: public AllocatorBenchmarkFixture<TAllocator>
|
||||
{
|
||||
using base = AllocatorBenchmarkFixture<TAllocator>;
|
||||
using TestAllocatorType = typename base::TestAllocatorType;
|
||||
|
||||
public:
|
||||
void Benchmark(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state)
|
||||
{
|
||||
state.PauseTiming();
|
||||
AZStd::vector<void*>& perThreadAllocations = base::GetPerThreadAllocations(state.thread_index);
|
||||
|
||||
const size_t numberOfAllocations = perThreadAllocations.size();
|
||||
size_t totalAllocationSize = 0;
|
||||
for (size_t allocationIndex = 0; allocationIndex < numberOfAllocations; ++allocationIndex)
|
||||
{
|
||||
const AllocationSizeArray& allocationArray = s_allocationSizes[TAllocationSize];
|
||||
const size_t allocationSize = allocationArray[allocationIndex % allocationArray.size()];
|
||||
totalAllocationSize += allocationSize;
|
||||
perThreadAllocations[allocationIndex] = TestAllocatorType::Allocate(allocationSize, 0);
|
||||
}
|
||||
|
||||
for (size_t allocationIndex = 0; allocationIndex < numberOfAllocations; ++allocationIndex)
|
||||
{
|
||||
const AllocationSizeArray& allocationArray = s_allocationSizes[TAllocationSize];
|
||||
const size_t allocationSize = allocationArray[allocationIndex % allocationArray.size()];
|
||||
state.ResumeTiming();
|
||||
TestAllocatorType::DeAllocate(perThreadAllocations[allocationIndex], allocationSize);
|
||||
state.PauseTiming();
|
||||
perThreadAllocations[allocationIndex] = nullptr;
|
||||
}
|
||||
|
||||
state.counters[s_counterAllocatorMemory] = benchmark::Counter(static_cast<double>(TestAllocatorType::NumAllocatedBytes()), benchmark::Counter::kDefaults);
|
||||
state.counters[s_counterBenchmarkMemory] = benchmark::Counter(static_cast<double>(totalAllocationSize), benchmark::Counter::kDefaults);
|
||||
|
||||
state.SetItemsProcessed(numberOfAllocations);
|
||||
|
||||
TestAllocatorType::GarbageCollect();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TAllocator>
|
||||
class RecordedAllocationBenchmarkFixture : public ::benchmark::Fixture
|
||||
{
|
||||
using TestAllocatorType = TestAllocatorWrapper<TAllocator>;
|
||||
|
||||
virtual void internalSetUp()
|
||||
{
|
||||
TestAllocatorType::SetUp();
|
||||
}
|
||||
|
||||
void internalTearDown()
|
||||
{
|
||||
TestAllocatorType::TearDown();
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct alignas(1) AllocatorOperation
|
||||
{
|
||||
enum OperationType : size_t
|
||||
{
|
||||
ALLOCATE,
|
||||
DEALLOCATE
|
||||
};
|
||||
OperationType m_type : 1;
|
||||
size_t m_size : 28; // Can represent up to 256Mb requests
|
||||
size_t m_alignment : 7; // Can represent up to 128 alignment
|
||||
size_t m_recordId : 28; // Can represent up to 256M simultaneous requests, we reuse ids
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(AllocatorOperation) == 8);
|
||||
|
||||
public:
|
||||
void SetUp(const ::benchmark::State&) override
|
||||
{
|
||||
internalSetUp();
|
||||
}
|
||||
void SetUp(::benchmark::State&) override
|
||||
{
|
||||
internalSetUp();
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State&) override
|
||||
{
|
||||
internalTearDown();
|
||||
}
|
||||
void TearDown(::benchmark::State&) override
|
||||
{
|
||||
internalTearDown();
|
||||
}
|
||||
|
||||
void Benchmark(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state)
|
||||
{
|
||||
state.PauseTiming();
|
||||
|
||||
AZStd::unordered_map<size_t, void*> pointerRemapping;
|
||||
constexpr size_t allocationOperationCount = 5 * 1024;
|
||||
AZStd::array<AllocatorOperation, allocationOperationCount> m_operations = {};
|
||||
[[maybe_unused]] const size_t operationSize = sizeof(AllocatorOperation);
|
||||
|
||||
size_t totalAllocationSize = 0;
|
||||
size_t itemsProcessed = 0;
|
||||
|
||||
for (size_t i = 0; i < 100; ++i) // play the recording multiple times to get a good stable sample, this way we can keep a smaller recording
|
||||
{
|
||||
AZ::IO::SystemFile file;
|
||||
AZ::IO::FixedMaxPathString filePath = AZ::Utils::GetExecutableDirectory();
|
||||
filePath += "/Tests/AzCore/Memory/AllocatorBenchmarkRecordings.bin";
|
||||
if (!file.Open(filePath.c_str(), AZ::IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
size_t elementsRead =
|
||||
file.Read(sizeof(AllocatorOperation) * allocationOperationCount, &m_operations) / sizeof(AllocatorOperation);
|
||||
itemsProcessed += elementsRead;
|
||||
|
||||
while (elementsRead > 0)
|
||||
{
|
||||
for (size_t operationIndex = 0; operationIndex < elementsRead; ++operationIndex)
|
||||
{
|
||||
const AllocatorOperation& operation = m_operations[operationIndex];
|
||||
if (operation.m_type == AllocatorOperation::ALLOCATE)
|
||||
{
|
||||
const auto it = pointerRemapping.emplace(operation.m_recordId, nullptr);
|
||||
if (it.second) // otherwise already allocated
|
||||
{
|
||||
state.ResumeTiming();
|
||||
void* ptr = TestAllocatorType::Allocate(operation.m_size, operation.m_alignment);
|
||||
state.PauseTiming();
|
||||
totalAllocationSize += operation.m_size;
|
||||
it.first->second = ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Doing a resize, dont account for this memory change, this operation is rare and we dont have
|
||||
// the size of the previous allocation
|
||||
state.ResumeTiming();
|
||||
TestAllocatorType::Resize(it.first->second, operation.m_size);
|
||||
state.PauseTiming();
|
||||
}
|
||||
}
|
||||
else // AllocatorOperation::DEALLOCATE:
|
||||
{
|
||||
if (operation.m_recordId)
|
||||
{
|
||||
const auto ptrIt = pointerRemapping.find(operation.m_recordId);
|
||||
if (ptrIt != pointerRemapping.end())
|
||||
{
|
||||
totalAllocationSize -= operation.m_size;
|
||||
state.ResumeTiming();
|
||||
TestAllocatorType::DeAllocate(
|
||||
ptrIt->second,
|
||||
/*operation.m_size*/ 0); // size is not correct after a resize, a 0 size deals with it
|
||||
state.PauseTiming();
|
||||
pointerRemapping.erase(ptrIt);
|
||||
}
|
||||
}
|
||||
else // deallocate(nullptr) are recorded
|
||||
{
|
||||
// Just to account of the call of deallocate(nullptr);
|
||||
state.ResumeTiming();
|
||||
TestAllocatorType::DeAllocate(nullptr, /*operation.m_size*/ 0);
|
||||
state.PauseTiming();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elementsRead =
|
||||
file.Read(sizeof(AllocatorOperation) * allocationOperationCount, &m_operations) / sizeof(AllocatorOperation);
|
||||
itemsProcessed += elementsRead;
|
||||
}
|
||||
file.Close();
|
||||
|
||||
// Deallocate the remainder (since we stopped the recording middle-game)(there are leaks as well)
|
||||
for (const auto& pointerMapping : pointerRemapping)
|
||||
{
|
||||
state.ResumeTiming();
|
||||
TestAllocatorType::DeAllocate(pointerMapping.second);
|
||||
state.PauseTiming();
|
||||
}
|
||||
itemsProcessed += pointerRemapping.size();
|
||||
pointerRemapping.clear();
|
||||
}
|
||||
|
||||
state.counters[s_counterAllocatorMemory] = benchmark::Counter(static_cast<double>(TestAllocatorType::NumAllocatedBytes()), benchmark::Counter::kDefaults);
|
||||
state.counters[s_counterBenchmarkMemory] = benchmark::Counter(static_cast<double>(totalAllocationSize), benchmark::Counter::kDefaults);
|
||||
|
||||
state.SetItemsProcessed(itemsProcessed);
|
||||
|
||||
TestAllocatorType::GarbageCollect();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For non-threaded ranges, run 100, 400, 1600 amounts
|
||||
static void RunRanges(benchmark::internal::Benchmark* b)
|
||||
{
|
||||
for (int i = 0; i < 6; i += 2)
|
||||
{
|
||||
b->Arg((1 << i) * 100);
|
||||
}
|
||||
}
|
||||
static void RecordedRunRanges(benchmark::internal::Benchmark* b)
|
||||
{
|
||||
b->Iterations(1);
|
||||
}
|
||||
|
||||
// For threaded ranges, run just 200, multi-threaded will already multiply by thread
|
||||
static void ThreadedRunRanges(benchmark::internal::Benchmark* b)
|
||||
{
|
||||
b->Arg(100);
|
||||
}
|
||||
|
||||
// Test under and over-subscription of threads vs the amount of CPUs available
|
||||
static const unsigned int MaxThreadRange = 2 * AZStd::thread::hardware_concurrency();
|
||||
|
||||
#define BM_REGISTER_TEMPLATE(FIXTURE, TESTNAME, ...) \
|
||||
BENCHMARK_TEMPLATE_DEFINE_F(FIXTURE, TESTNAME, __VA_ARGS__)(benchmark::State& state) { Benchmark(state); } \
|
||||
BENCHMARK_REGISTER_F(FIXTURE, TESTNAME)
|
||||
|
||||
// We test small/big/mixed allocations in single-threaded environments. For multi-threaded environments, we test mixed since
|
||||
// the multi threaded fixture will run multiple passes (1, 2, 4, ... until 2*hardware_concurrency)
|
||||
#define BM_REGISTER_SIZE_FIXTURES(FIXTURE, TESTNAME, ALLOCATORTYPE) \
|
||||
BM_REGISTER_TEMPLATE(FIXTURE, TESTNAME##_SMALL, ALLOCATORTYPE, SMALL)->Apply(RunRanges); \
|
||||
BM_REGISTER_TEMPLATE(FIXTURE, TESTNAME##_BIG, ALLOCATORTYPE, BIG)->Apply(RunRanges); \
|
||||
BM_REGISTER_TEMPLATE(FIXTURE, TESTNAME##_MIXED, ALLOCATORTYPE, MIXED)->Apply(RunRanges); \
|
||||
BM_REGISTER_TEMPLATE(FIXTURE, TESTNAME##_MIXED_THREADED, ALLOCATORTYPE, MIXED)->ThreadRange(2, MaxThreadRange)->Apply(ThreadedRunRanges);
|
||||
|
||||
#define BM_REGISTER_ALLOCATOR(TESTNAME, ALLOCATORTYPE) \
|
||||
namespace BM_##TESTNAME \
|
||||
{ \
|
||||
BM_REGISTER_SIZE_FIXTURES(AllocationBenchmarkFixture, TESTNAME, ALLOCATORTYPE); \
|
||||
BM_REGISTER_SIZE_FIXTURES(DeAllocationBenchmarkFixture, TESTNAME, ALLOCATORTYPE); \
|
||||
BM_REGISTER_TEMPLATE(RecordedAllocationBenchmarkFixture, TESTNAME, ALLOCATORTYPE)->Apply(RecordedRunRanges); \
|
||||
}
|
||||
|
||||
/// Warm up benchmark used to prepare the OS for allocations. Most OS keep allocations for a process somehow
|
||||
/// reserved. So the first allocations run always get a bigger impact in a process. This warm up allocator runs
|
||||
/// all the benchmarks and is just used for the the next allocators to report more consistent results.
|
||||
BM_REGISTER_ALLOCATOR(WarmUpAllocator, RawMallocAllocator);
|
||||
|
||||
BM_REGISTER_ALLOCATOR(RawMallocAllocator, RawMallocAllocator);
|
||||
BM_REGISTER_ALLOCATOR(MallocSchemaAllocator, MallocSchemaAllocator);
|
||||
BM_REGISTER_ALLOCATOR(HphaSchemaAllocator, HphaSchemaAllocator);
|
||||
BM_REGISTER_ALLOCATOR(SystemAllocator, TestSystemAllocator);
|
||||
|
||||
//BM_REGISTER_ALLOCATOR(BestFitExternalMapAllocator, BestFitExternalMapAllocator); // Requires to pre-allocate blocks and cannot work as a general-purpose allocator
|
||||
//BM_REGISTER_ALLOCATOR(HeapSchemaAllocator, TestHeapSchemaAllocator); // Requires to pre-allocate blocks and cannot work as a general-purpose allocator
|
||||
//BM_REGISTER_SCHEMA(PoolSchema); // Requires special alignment requests while allocating
|
||||
|
||||
#undef BM_REGISTER_ALLOCATOR
|
||||
#undef BM_REGISTER_SIZE_FIXTURES
|
||||
#undef BM_REGISTER_TEMPLATE
|
||||
|
||||
} // Benchmark
|
||||
|
||||
#endif // HAVE_BENCHMARK
|
||||
@@ -10,10 +10,6 @@
|
||||
#include <AzCore/Memory/HphaSchema.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
#if defined(HAVE_BENCHMARK)
|
||||
#include <benchmark/benchmark.h>
|
||||
#endif // HAVE_BENCHMARK
|
||||
|
||||
class HphaSchema_TestAllocator
|
||||
: public AZ::SimpleSchemaAllocator<AZ::HphaSchema>
|
||||
{
|
||||
@@ -112,87 +108,3 @@ namespace UnitTest
|
||||
HphaSchemaTestFixture,
|
||||
::testing::ValuesIn(s_mixedInstancesParameters));
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_BENCHMARK)
|
||||
namespace Benchmark
|
||||
{
|
||||
class HphaSchemaBenchmarkFixture
|
||||
: public ::benchmark::Fixture
|
||||
{
|
||||
void internalSetUp()
|
||||
{
|
||||
AZ::AllocatorInstance<HphaSchema_TestAllocator>::Create();
|
||||
}
|
||||
|
||||
void internalTearDown()
|
||||
{
|
||||
AZ::AllocatorInstance<HphaSchema_TestAllocator>::Destroy();
|
||||
}
|
||||
|
||||
public:
|
||||
void SetUp(const benchmark::State&) override
|
||||
{
|
||||
internalSetUp();
|
||||
}
|
||||
void SetUp(benchmark::State&) override
|
||||
{
|
||||
internalSetUp();
|
||||
}
|
||||
void TearDown(const benchmark::State&) override
|
||||
{
|
||||
internalTearDown();
|
||||
}
|
||||
void TearDown(benchmark::State&) override
|
||||
{
|
||||
internalTearDown();
|
||||
}
|
||||
|
||||
static void BM_Allocations(benchmark::State& state, const AllocationSizeArray& allocationArray)
|
||||
{
|
||||
AZStd::vector<void*> allocations;
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
state.PauseTiming();
|
||||
const size_t allocationIndex = allocations.size();
|
||||
const size_t allocationSize = allocationArray[allocationIndex % allocationArray.size()];
|
||||
|
||||
state.ResumeTiming();
|
||||
void* allocation = AZ::AllocatorInstance<HphaSchema_TestAllocator>::Get().Allocate(allocationSize, 0);
|
||||
|
||||
state.PauseTiming();
|
||||
allocations.emplace_back(allocation);
|
||||
|
||||
state.ResumeTiming();
|
||||
}
|
||||
|
||||
const size_t numberOfAllocations = allocations.size();
|
||||
state.SetItemsProcessed(numberOfAllocations);
|
||||
|
||||
for (size_t allocationIndex = 0; allocationIndex < numberOfAllocations; ++allocationIndex)
|
||||
{
|
||||
AZ::AllocatorInstance<HphaSchema_TestAllocator>::Get().DeAllocate(allocations[allocationIndex], allocationArray[allocationIndex % allocationArray.size()]);
|
||||
}
|
||||
AZ::AllocatorInstance<HphaSchema_TestAllocator>::Get().GarbageCollect();
|
||||
}
|
||||
};
|
||||
|
||||
// Small allocations, these are allocations that are going to end up in buckets in the HphaSchema
|
||||
BENCHMARK_F(HphaSchemaBenchmarkFixture, SmallAllocations)(benchmark::State& state)
|
||||
{
|
||||
BM_Allocations(state, s_smallAllocationSizes);
|
||||
}
|
||||
|
||||
BENCHMARK_F(HphaSchemaBenchmarkFixture, BigAllocations)(benchmark::State& state)
|
||||
{
|
||||
BM_Allocations(state, s_bigAllocationSizes);
|
||||
}
|
||||
|
||||
BENCHMARK_F(HphaSchemaBenchmarkFixture, MixedAllocations)(benchmark::State& state)
|
||||
{
|
||||
BM_Allocations(state, s_mixedAllocationSizes);
|
||||
}
|
||||
|
||||
|
||||
} // Benchmark
|
||||
#endif // HAVE_BENCHMARK
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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/PlatformIncl.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
namespace Benchmark
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
size_t GetProcessMemoryUsageBytes()
|
||||
{
|
||||
struct rusage rusage;
|
||||
getrusage(RUSAGE_SELF, &rusage);
|
||||
return rusage.ru_maxrss * 1024L;
|
||||
}
|
||||
|
||||
size_t GetMemorySize(void* memory)
|
||||
{
|
||||
return memory ? malloc_usable_size(memory) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,5 @@
|
||||
|
||||
set(FILES
|
||||
Tests/UtilsTests_Android.cpp
|
||||
Tests/Memory/AllocatorBenchmarks_Android.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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/PlatformIncl.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
namespace Benchmark
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
size_t GetProcessMemoryUsageBytes()
|
||||
{
|
||||
struct rusage rusage;
|
||||
getrusage(RUSAGE_SELF, &rusage);
|
||||
return rusage.ru_maxrss * 1024L;
|
||||
}
|
||||
|
||||
size_t GetMemorySize(void* memory)
|
||||
{
|
||||
return memory ? malloc_usable_size(memory) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,5 @@
|
||||
set(FILES
|
||||
Tests/UtilsTests_Linux.cpp
|
||||
../Common/UnixLike/Tests/UtilsTests_UnixLike.cpp
|
||||
Tests/Memory/AllocatorBenchmarks_Linux.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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/PlatformIncl.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
|
||||
#include <malloc/malloc.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
namespace Benchmark
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
size_t GetProcessMemoryUsageBytes()
|
||||
{
|
||||
struct rusage rusage;
|
||||
getrusage(RUSAGE_SELF, &rusage);
|
||||
return rusage.ru_maxrss;
|
||||
}
|
||||
|
||||
size_t GetMemorySize(void* memory)
|
||||
{
|
||||
return memory ? malloc_size(memory) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,5 @@
|
||||
set(FILES
|
||||
../Common/Apple/Tests/UtilsTests_Apple.cpp
|
||||
../Common/UnixLike/Tests/UtilsTests_UnixLike.cpp
|
||||
Tests/Memory/AllocatorBenchmarks_Mac.cpp
|
||||
)
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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/PlatformIncl.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <psapi.h>
|
||||
|
||||
namespace Benchmark
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
size_t GetProcessMemoryUsageBytes()
|
||||
{
|
||||
EmptyWorkingSet(GetCurrentProcess());
|
||||
|
||||
size_t memoryUsage = 0;
|
||||
MEMORY_BASIC_INFORMATION mbi = { 0 };
|
||||
unsigned char* pEndRegion = nullptr;
|
||||
while (sizeof(mbi) == VirtualQuery(pEndRegion, &mbi, sizeof(mbi))) {
|
||||
pEndRegion += mbi.RegionSize;
|
||||
if ((mbi.AllocationProtect & PAGE_READWRITE) && (mbi.State & MEM_COMMIT)) {
|
||||
memoryUsage += mbi.RegionSize;
|
||||
}
|
||||
}
|
||||
return memoryUsage;
|
||||
}
|
||||
|
||||
size_t GetMemorySize(void* memory)
|
||||
{
|
||||
return memory ? _aligned_msize(memory, 1, 0) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
set(FILES
|
||||
../Common/WinAPI/Tests/UtilsTests_WinAPI.cpp
|
||||
Tests/IO/Streamer/StorageDriveTests_Windows.cpp
|
||||
Tests/Memory/AllocatorBenchmarks_Windows.cpp
|
||||
Tests/Memory/OverrunDetectionAllocator_Windows.cpp
|
||||
Tests/Serialization_Windows.cpp
|
||||
)
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <AzCore/Math/Obb.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
|
||||
#include <Math/MathTest.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
namespace UnitTest
|
||||
@@ -1409,13 +1411,17 @@ namespace UnitTest
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetNormal().y,-1)");
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetNormal().z,0)");
|
||||
|
||||
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
|
||||
script->Execute("pl:Set(12, 13, 14, 15)");
|
||||
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetDistance(), 15)");
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetNormal().x, 12)");
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetNormal().y, 13)");
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetNormal().z, 14)");
|
||||
|
||||
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
|
||||
script->Execute("pl:Set(Vector3(22, 23, 24), 25)");
|
||||
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetDistance(), 25)");
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetNormal().x, 22)");
|
||||
script->Execute("AZTestAssertFloatClose(pl:GetNormal().y, 23)");
|
||||
@@ -1493,7 +1499,9 @@ namespace UnitTest
|
||||
|
||||
script->Execute("pl:Set(1, 0, 0, 0)");
|
||||
script->Execute("AZTestAssert(pl:IsFinite())");
|
||||
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
|
||||
script->Execute("pl:Set(math.huge, math.huge, math.huge, math.huge)");
|
||||
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
script->Execute("AZTestAssert( not pl:IsFinite())");
|
||||
}
|
||||
|
||||
|
||||
@@ -327,17 +327,13 @@ namespace JsonSerializationTests
|
||||
SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get());
|
||||
}
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
using JsonSerializationDeathTests = JsonRegistrationContextTests;
|
||||
TEST_F(JsonSerializationDeathTests, DoubleUnregisterSerializer_Asserts)
|
||||
TEST_F(JsonRegistrationContextTests, DoubleUnregisterSerializer_Asserts)
|
||||
{
|
||||
ASSERT_DEATH({
|
||||
SerializerWithOneType::Reflect(m_jsonRegistrationContext.get());
|
||||
SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get());
|
||||
SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get());
|
||||
}, ".*"
|
||||
);
|
||||
SerializerWithOneType::Reflect(m_jsonRegistrationContext.get());
|
||||
SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get());
|
||||
AZ_TEST_START_ASSERTTEST;
|
||||
SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get());
|
||||
AZ_TEST_STOP_ASSERTTEST(1);
|
||||
}
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
} //namespace JsonSerializationTests
|
||||
|
||||
@@ -148,6 +148,7 @@ set(FILES
|
||||
Math/Matrix4x4PerformanceTests.cpp
|
||||
Math/Matrix4x4Tests.cpp
|
||||
Math/MatrixUtilsTests.cpp
|
||||
Math/MathTest.h
|
||||
Math/MathTestData.h
|
||||
Math/ObbPerformanceTests.cpp
|
||||
Math/ObbTests.cpp
|
||||
@@ -170,6 +171,7 @@ set(FILES
|
||||
Math/Vector3Tests.cpp
|
||||
Math/Vector4PerformanceTests.cpp
|
||||
Math/Vector4Tests.cpp
|
||||
Memory/AllocatorBenchmarks.cpp
|
||||
Memory/AllocatorManager.cpp
|
||||
Memory/HphaSchema.cpp
|
||||
Memory/HphaSchemaErrorDetection.cpp
|
||||
|
||||
@@ -270,8 +270,6 @@ set(FILES
|
||||
Physics/WindBus.h
|
||||
Process/ProcessCommunicator.cpp
|
||||
Process/ProcessCommunicator.h
|
||||
Process/ProcessWatcher.cpp
|
||||
Process/ProcessWatcher.h
|
||||
Process/ProcessCommon_fwd.h
|
||||
Process/ProcessCommunicator.h
|
||||
Process/ProcessWatcher.cpp
|
||||
|
||||
+5
@@ -83,4 +83,9 @@ namespace AzFramework
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AZStd::string ProcessLauncher::ProcessLaunchInfo::GetCommandLineParametersAsString() const
|
||||
{
|
||||
return AZStd::string{};
|
||||
}
|
||||
} //namespace AzFramework
|
||||
|
||||
Reference in New Issue
Block a user