Merge remote-tracking branch 'upstream/development' into compiletime_filerequest_code2

This commit is contained in:
nemerle
2022-01-08 21:25:48 +01:00
785 changed files with 141969 additions and 22455 deletions
@@ -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);
}
}
@@ -11,6 +11,7 @@
#include <AzCore/Math/Matrix3x3.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AZTestShared/Math/MathTestHelpers.h>
using namespace AZ;
@@ -453,7 +454,7 @@ namespace UnitTest
AZ::Quaternion backFromScaledAxisAngle = AZ::Quaternion::CreateFromScaledAxisAngle(scaledAxisAngle);
// Compare the original quaternion with the one after the conversion.
EXPECT_TRUE(testQuat.IsClose(backFromScaledAxisAngle, 1e-6f));
EXPECT_THAT(testQuat, IsCloseTolerance(backFromScaledAxisAngle, 1e-6f));
}
TEST_P(QuaternionScaledAxisAngleConversionFixture, AxisAngleQuatRoundtripTests)
@@ -467,7 +468,7 @@ namespace UnitTest
// Convert the axis-angle back into a quaternion and compare the original quaternion with the one after the conversion.
const AZ::Quaternion backFromAxisAngle = AZ::Quaternion::CreateFromAxisAngle(axis, angle);
EXPECT_TRUE(testQuat.IsClose(backFromAxisAngle, 1e-6f));
EXPECT_THAT(testQuat, IsCloseTolerance(backFromAxisAngle, 1e-6f));
}
TEST_P(QuaternionScaledAxisAngleConversionFixture, CompareAxisAngleConversionTests)
@@ -506,8 +507,20 @@ namespace UnitTest
}
const AZ::Quaternion backFromAxisAngle = AZ::Quaternion::CreateFromAxisAngle(axisFromScaledResult, angleFromScaledResult);
EXPECT_TRUE(testQuat.IsClose(backFromAxisAngle, 1e-6f));
EXPECT_THAT(testQuat, IsCloseTolerance(backFromAxisAngle, 1e-6f));
}
INSTANTIATE_TEST_CASE_P(MATH_Quaternion, QuaternionScaledAxisAngleConversionFixture, ::testing::ValuesIn(RotationRepresentationConversionTestQuats));
TEST(MATH_Quaternion, ShortestEquivalent)
{
const AZ::Quaternion testQuat = AZ::Quaternion::CreateRotationX(AZ::Constants::HalfPi * 3.0f);
AZ::Quaternion absQuat = testQuat;
absQuat.ShortestEquivalent();
EXPECT_THAT(testQuat.GetShortestEquivalent(), IsCloseTolerance(absQuat, 1e-6f));
const float angle = absQuat.GetEulerRadians().GetX();
EXPECT_THAT(angle, testing::FloatEq(-AZ::Constants::HalfPi));
}
}
@@ -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
@@ -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
)
@@ -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
@@ -0,0 +1,106 @@
/*
* 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/IO/Path/Path.h>
#include <AzCore/IO/Path/PathReflect.h>
#include <AzCore/Serialization/Json/PathSerializer.h>
#include <Tests/Serialization/Json/BaseJsonSerializerFixture.h>
#include <Tests/Serialization/Json/JsonSerializerConformityTests.h>
namespace JsonSerializationTests
{
template<typename PathType>
class PathTestDescription
: public JsonSerializerConformityTestDescriptor<PathType>
{
public:
using JsonSerializerConformityTestDescriptor<PathType>::Reflect;
void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& serializeContext) override
{
AZ::IO::PathReflect(serializeContext.get());
}
void Reflect(AZStd::unique_ptr<AZ::JsonRegistrationContext>& jsonContext) override
{
AZ::IO::PathReflect(jsonContext.get());
}
AZStd::shared_ptr<AZ::BaseJsonSerializer> CreateSerializer() override
{
return AZStd::make_shared<AZ::JsonPathSerializer>();
}
AZStd::shared_ptr<PathType> CreateDefaultInstance() override
{
return AZStd::make_shared<PathType>();
}
AZStd::shared_ptr<PathType> CreateFullySetInstance() override
{
return AZStd::make_shared<PathType>("O3DE/Relative/Path");
}
AZStd::string_view GetJsonForFullySetInstance() override
{
return R"("O3DE/Relative/Path")";
}
void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override
{
features.EnableJsonType(rapidjson::kStringType);
features.m_supportsPartialInitialization = false;
features.m_supportsInjection = false;
}
bool AreEqual(const PathType& lhs, const PathType& rhs) override
{
return lhs == rhs;
}
};
using PathConformityTestTypes = ::testing::Types<
PathTestDescription<AZ::IO::Path>,
PathTestDescription<AZ::IO::FixedMaxPath>
>;
INSTANTIATE_TYPED_TEST_CASE_P(Path, JsonSerializerConformityTests, PathConformityTestTypes);
class PathSerializerTests
: public BaseJsonSerializerFixture
{
public:
AZStd::unique_ptr<AZ::JsonPathSerializer> m_serializer;
void SetUp() override
{
BaseJsonSerializerFixture::SetUp();
m_serializer = AZStd::make_unique<AZ::JsonPathSerializer>();
}
void TearDown() override
{
m_serializer.reset();
BaseJsonSerializerFixture::TearDown();
}
};
TEST_F(PathSerializerTests, LoadingIntoFixedMaxPath_GreaterThanMaxPathLength_Fails)
{
AZ::IO::Path testPath;
// Fill a path greater than the AZ::IO::MaxPathLength in write it to Json
testPath.Native().append(AZ::IO::MaxPathLength + 2, 'a');
rapidjson::Value loadPathValue;
AZ::JsonSerializationResult::ResultCode resultCode = m_serializer->Store(loadPathValue,
&testPath, nullptr, azrtti_typeid<AZ::IO::Path>(), *m_jsonSerializationContext);
EXPECT_EQ(AZ::JsonSerializationResult::Outcomes::Success, resultCode.GetOutcome());
AZ::IO::FixedMaxPath resultPath;
AZ::JsonSerializationResult::ResultCode result = m_serializer->Load(&resultPath, azrtti_typeid<AZ::IO::FixedMaxPath>(),
loadPathValue, *m_jsonDeserializationContext);
EXPECT_GE(result.GetOutcome(), AZ::JsonSerializationResult::Outcomes::Invalid);
}
} // namespace JsonSerializationTests
@@ -10,6 +10,77 @@
#include <Tests/Serialization/Json/JsonSerializationTests.h>
#include <Tests/Serialization/Json/TestCases_Classes.h>
#include <Tests/Serialization/Json/TestCases_Pointers.h>
#include <AzCore/Asset/AssetCommon.h>
namespace AZ
{
template<typename T>
struct SerializeGenericTypeInfo<JsonSerializationTests::TemplatedClass<T>>
{
using ThisType = JsonSerializationTests::TemplatedClass<T>;
class GenericTemplatedClassInfo : public GenericClassInfo
{
public:
GenericTemplatedClassInfo()
: m_classData{ SerializeContext::ClassData::Create<ThisType>(
"TemplatedClass", "{CA4ADF74-66E7-4D16-B4AC-F71278C60EC7}", nullptr, nullptr) }
{
}
SerializeContext::ClassData* GetClassData() override
{
return &m_classData;
}
size_t GetNumTemplatedArguments() override
{
return 1;
}
const Uuid& GetSpecializedTypeId() const override
{
return m_classData.m_typeId;
}
const Uuid& GetGenericTypeId() const override
{
return m_classData.m_typeId;
}
const Uuid& GetTemplatedTypeId(size_t element) override
{
(void)element;
return SerializeGenericTypeInfo<T>::GetClassTypeId();
}
void Reflect(SerializeContext* serializeContext) override
{
if (serializeContext)
{
serializeContext->RegisterGenericClassInfo(
GetSpecializedTypeId(), this, &AZ::AnyTypeInfoConcept<Data::Asset<Data::AssetData>>::CreateAny);
serializeContext->RegisterGenericClassInfo(
azrtti_typeid<ThisType>(), this,
&AZ::AnyTypeInfoConcept<ThisType>::CreateAny);
}
}
SerializeContext::ClassData m_classData;
};
using ClassInfoType = GenericTemplatedClassInfo;
static ClassInfoType* GetGenericInfo()
{
return GetCurrentSerializeContextModule().CreateGenericClassInfo<ThisType>();
}
static const Uuid& GetClassTypeId()
{
return GetGenericInfo()->GetClassData()->m_typeId;
}
};
} // namespace AZ
namespace JsonSerializationTests
{
@@ -286,4 +357,32 @@ namespace JsonSerializationTests
EXPECT_EQ(Processing::Halted, result.GetProcessing());
EXPECT_EQ(Outcomes::Unknown, result.GetOutcome());
}
TEST_F(JsonSerializationTests, StoreTypeId_TemplatedType_StoresUuidWithName)
{
using namespace AZ;
using namespace AZ::JsonSerializationResult;
m_serializeContext->RegisterGenericType<TemplatedClass<A::Inherited>>();
m_serializeContext->RegisterGenericType<TemplatedClass<BaseClass>>();
Uuid input = azrtti_typeid<TemplatedClass<A::Inherited>>();
ResultCode result = JsonSerialization::StoreTypeId(
*m_jsonDocument, m_jsonDocument->GetAllocator(), input, AZStd::string_view{}, *m_serializationSettings);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
AZStd::string expected =
AZStd::string::format(R"("%s TemplatedClass")", azrtti_typeid<TemplatedClass<A::Inherited>>().ToString<AZStd::string>().c_str());
Expect_DocStrEq(expected.c_str(), false);
input = azrtti_typeid<TemplatedClass<BaseClass>>();
result = JsonSerialization::StoreTypeId(
*m_jsonDocument, m_jsonDocument->GetAllocator(), input, AZStd::string_view{}, *m_serializationSettings);
expected =
AZStd::string::format(R"("%s TemplatedClass")", azrtti_typeid<TemplatedClass<BaseClass>>().ToString<AZStd::string>().c_str());
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq(expected.c_str(), false);
}
} // namespace JsonSerializationTests
@@ -11,8 +11,7 @@
namespace UnitTest
{
class TimeTests
: public AllocatorsFixture
class TimeTests : public AllocatorsFixture
{
public:
void SetUp() override
@@ -77,4 +76,4 @@ namespace UnitTest
int64_t delta = static_cast<int64_t>(timeMs) - static_cast<int64_t>(timeUsToMs);
EXPECT_LT(abs(delta), 1);
}
}
} // namespace UnitTest
@@ -111,6 +111,7 @@ set(FILES
Serialization/Json/MapSerializerTests.cpp
Serialization/Json/MathVectorSerializerTests.cpp
Serialization/Json/MathMatrixSerializerTests.cpp
Serialization/Json/PathSerializerTests.cpp
Serialization/Json/SmartPointerSerializerTests.cpp
Serialization/Json/StringSerializerTests.cpp
Serialization/Json/TestCases.h
@@ -147,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
@@ -169,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