diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp index c604373296..bc5c2b28cf 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp @@ -77,8 +77,8 @@ namespace AZ::Dom::Utils for (size_t i = 0; i < ourValues.size(); ++i) { const Object::EntryType& lhsChild = ourValues[i]; - const Object::EntryType& rhsChild = theirValues[i]; - if (lhsChild.first != rhsChild.first || !DeepCompareIsEqual(lhsChild.second, rhsChild.second)) + auto rhsIt = rhs.FindMember(lhsChild.first); + if (rhsIt == rhs.MemberEnd() || !DeepCompareIsEqual(lhsChild.second, rhsIt->second)) { return false; } @@ -144,8 +144,8 @@ namespace AZ::Dom::Utils for (size_t i = 0; i < ourProperties.size(); ++i) { const Object::EntryType& lhsChild = ourProperties[i]; - const Object::EntryType& rhsChild = theirProperties[i]; - if (lhsChild.first != rhsChild.first || !DeepCompareIsEqual(lhsChild.second, rhsChild.second)) + auto rhsIt = rhs.FindMember(lhsChild.first); + if (rhsIt == rhs.MemberEnd() || !DeepCompareIsEqual(lhsChild.second, rhsIt->second)) { return false; } diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp index 6d944c9f45..10c8e33715 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp @@ -283,64 +283,33 @@ namespace AZ::Dom Type Dom::Value::GetType() const { - return AZStd::visit( - [](auto&& value) -> Type - { - using CurrentType = AZStd::decay_t; - if constexpr (AZStd::is_same_v) - { - return Type::Null; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Int64; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Uint64; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Double; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Bool; - } - else if constexpr (AZStd::is_same_v) - { - return Type::String; - } - else if constexpr (AZStd::is_same_v) - { - return Type::String; - } - else if constexpr (AZStd::is_same_v) - { - return Type::String; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Object; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Array; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Node; - } - else if constexpr (AZStd::is_same_v) - { - return Type::Opaque; - } - else - { - AZ_Assert(false, "AZ::Dom::Value::GetType: m_value has an unexpected type"); - } - }, - m_value); + switch (m_value.index()) + { + case GetTypeIndex(): + return Type::Null; + case GetTypeIndex(): + return Type::Int64; + case GetTypeIndex(): + return Type::Uint64; + case GetTypeIndex(): + return Type::Double; + case GetTypeIndex(): + return Type::Bool; + case GetTypeIndex(): + case GetTypeIndex(): + case GetTypeIndex(): + return Type::String; + case GetTypeIndex(): + return Type::Object; + case GetTypeIndex(): + return Type::Array; + case GetTypeIndex(): + return Type::Node; + case GetTypeIndex>(): + return Type::Opaque; + } + AZ_Assert(false, "AZ::Dom::Value::GetType: m_value has an unexpected type"); + return Type::Null; } bool Value::IsNull() const @@ -594,12 +563,12 @@ namespace AZ::Dom return GetObjectInternal().end(); } - Object::Iterator Value::MemberBegin() + Object::Iterator Value::MutableMemberBegin() { return GetObjectInternal().begin(); } - Object::Iterator Value::MemberEnd() + Object::Iterator Value::MutableMemberEnd() { return GetObjectInternal().end(); } @@ -725,12 +694,12 @@ namespace AZ::Dom return object.end(); } - Object::Iterator Value::EraseMember(Object::ConstIterator pos) + Object::Iterator Value::EraseMember(Object::Iterator pos) { return GetObjectInternal().erase(pos); } - Object::Iterator Value::EraseMember(Object::ConstIterator first, Object::ConstIterator last) + Object::Iterator Value::EraseMember(Object::Iterator first, Object::Iterator last) { return GetObjectInternal().erase(first, last); } @@ -811,12 +780,12 @@ namespace AZ::Dom return GetArrayInternal().end(); } - Array::Iterator Value::ArrayBegin() + Array::Iterator Value::MutableArrayBegin() { return GetArrayInternal().begin(); } - Array::Iterator Value::ArrayEnd() + Array::Iterator Value::MutableArrayEnd() { return GetArrayInternal().end(); } @@ -843,12 +812,12 @@ namespace AZ::Dom return *this; } - Array::Iterator Value::ArrayErase(Array::ConstIterator pos) + Array::Iterator Value::ArrayErase(Array::Iterator pos) { return GetArrayInternal().erase(pos); } - Array::Iterator Value::ArrayErase(Array::ConstIterator first, Array::ConstIterator last) + Array::Iterator Value::ArrayErase(Array::Iterator first, Array::Iterator last) { return GetArrayInternal().erase(first, last); } @@ -1113,6 +1082,10 @@ namespace AZ::Dom { result = visitor.RefCountedString(arg, copyStrings ? Lifetime::Temporary : Lifetime::Persistent); } + else if constexpr (AZStd::is_same_v) + { + result = visitor.String(arg, copyStrings ? Lifetime::Temporary : Lifetime::Persistent); + } else if constexpr (AZStd::is_same_v) { result = visitor.StartObject(); diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.h b/Code/Framework/AzCore/AzCore/DOM/DomValue.h index ecf8326525..d1d3c1745d 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomValue.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.h @@ -268,8 +268,8 @@ namespace AZ::Dom Object::ConstIterator MemberBegin() const; Object::ConstIterator MemberEnd() const; - Object::Iterator MemberBegin(); - Object::Iterator MemberEnd(); + Object::Iterator MutableMemberBegin(); + Object::Iterator MutableMemberEnd(); Object::Iterator FindMutableMember(KeyType name); Object::Iterator FindMutableMember(AZStd::string_view name); @@ -289,8 +289,8 @@ namespace AZ::Dom void RemoveMember(KeyType name); void RemoveMember(AZStd::string_view name); Object::Iterator RemoveMember(Object::Iterator pos); - Object::Iterator EraseMember(Object::ConstIterator pos); - Object::Iterator EraseMember(Object::ConstIterator first, Object::ConstIterator last); + Object::Iterator EraseMember(Object::Iterator pos); + Object::Iterator EraseMember(Object::Iterator first, Object::Iterator last); Object::Iterator EraseMember(KeyType name); Object::Iterator EraseMember(AZStd::string_view name); @@ -313,15 +313,15 @@ namespace AZ::Dom Array::ConstIterator ArrayBegin() const; Array::ConstIterator ArrayEnd() const; - Array::Iterator ArrayBegin(); - Array::Iterator ArrayEnd(); + Array::Iterator MutableArrayBegin(); + Array::Iterator MutableArrayEnd(); Value& ArrayReserve(size_t newCapacity); Value& ArrayPushBack(Value value); Value& ArrayPopBack(); - Array::Iterator ArrayErase(Array::ConstIterator pos); - Array::Iterator ArrayErase(Array::ConstIterator first, Array::ConstIterator last); + Array::Iterator ArrayErase(Array::Iterator pos); + Array::Iterator ArrayErase(Array::Iterator first, Array::Iterator last); Array::ContainerType& GetMutableArray(); const Array::ContainerType& GetArray() const; diff --git a/Code/Framework/AzCore/Tests/DOM/DomFixtures.cpp b/Code/Framework/AzCore/Tests/DOM/DomFixtures.cpp new file mode 100644 index 0000000000..236c1f6d74 --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomFixtures.cpp @@ -0,0 +1,189 @@ +/* + * 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 +#include +#include +#include + +namespace AZ::Dom::Tests +{ + void DomTestHarness::SetUpHarness() + { + NameDictionary::Create(); + AZ::AllocatorInstance::Create(); + } + + void DomTestHarness::TearDownHarness() + { + AZ::AllocatorInstance::Destroy(); + NameDictionary::Destroy(); + } + + void DomBenchmarkFixture::SetUp(const ::benchmark::State& st) + { + UnitTest::AllocatorsBenchmarkFixture::SetUp(st); + SetUpHarness(); + } + + void DomBenchmarkFixture::SetUp(::benchmark::State& st) + { + UnitTest::AllocatorsBenchmarkFixture::SetUp(st); + SetUpHarness(); + } + + void DomBenchmarkFixture::TearDown(::benchmark::State& st) + { + TearDownHarness(); + UnitTest::AllocatorsBenchmarkFixture::TearDown(st); + } + + void DomBenchmarkFixture::TearDown(const ::benchmark::State& st) + { + TearDownHarness(); + UnitTest::AllocatorsBenchmarkFixture::TearDown(st); + } + + rapidjson::Document DomBenchmarkFixture::GenerateDomJsonBenchmarkDocument(int64_t entryCount, int64_t stringTemplateLength) + { + rapidjson::Document document; + document.SetObject(); + + AZStd::string entryTemplate; + while (entryTemplate.size() < aznumeric_cast(stringTemplateLength)) + { + entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "; + } + entryTemplate.resize(stringTemplateLength); + AZStd::string buffer; + + auto createString = [&](int n) -> rapidjson::Value + { + buffer = AZStd::string::format("#%i %s", n, entryTemplate.c_str()); + return rapidjson::Value(buffer.data(), aznumeric_cast(buffer.size()), document.GetAllocator()); + }; + + auto createEntry = [&](int n) -> rapidjson::Value + { + rapidjson::Value entry(rapidjson::kObjectType); + entry.AddMember("string", createString(n), document.GetAllocator()); + entry.AddMember("int", rapidjson::Value(n), document.GetAllocator()); + entry.AddMember("double", rapidjson::Value(aznumeric_cast(n) * 0.5), document.GetAllocator()); + entry.AddMember("bool", rapidjson::Value(n % 2 == 0), document.GetAllocator()); + entry.AddMember("null", rapidjson::Value(rapidjson::kNullType), document.GetAllocator()); + return entry; + }; + + auto createArray = [&]() -> rapidjson::Value + { + rapidjson::Value array; + array.SetArray(); + for (int i = 0; i < entryCount; ++i) + { + array.PushBack(createEntry(i), document.GetAllocator()); + } + return array; + }; + + auto createObject = [&]() -> rapidjson::Value + { + rapidjson::Value object; + object.SetObject(); + for (int i = 0; i < entryCount; ++i) + { + buffer = AZStd::string::format("Key%i", i); + rapidjson::Value key; + key.SetString(buffer.data(), aznumeric_cast(buffer.length()), document.GetAllocator()); + object.AddMember(key.Move(), createArray(), document.GetAllocator()); + } + return object; + }; + + document.SetObject(); + document.AddMember("entries", createObject(), document.GetAllocator()); + + return document; + } + + AZStd::string DomBenchmarkFixture::GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) + { + rapidjson::Document document = GenerateDomJsonBenchmarkDocument(entryCount, stringTemplateLength); + + AZStd::string serializedJson; + auto result = AZ::JsonSerializationUtils::WriteJsonString(document, serializedJson); + AZ_Assert(result.IsSuccess(), "Failed to serialize generated JSON"); + return serializedJson; + } + + Value DomBenchmarkFixture::GenerateDomBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) + { + Value root(Type::Object); + + AZStd::string entryTemplate; + while (entryTemplate.size() < aznumeric_cast(stringTemplateLength)) + { + entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "; + } + entryTemplate.resize(stringTemplateLength); + AZStd::string buffer; + + auto createString = [&](int n) -> Value + { + return Value(AZStd::string::format("#%i %s", n, entryTemplate.c_str()), true); + }; + + auto createEntry = [&](int n) -> Value + { + Value entry(Type::Object); + entry.AddMember("string", createString(n)); + entry.AddMember("int", Value(n)); + entry.AddMember("double", Value(aznumeric_cast(n) * 0.5)); + entry.AddMember("bool", Value(n % 2 == 0)); + entry.AddMember("null", Value(Type::Null)); + return entry; + }; + + auto createArray = [&]() -> Value + { + Value array(Type::Array); + for (int i = 0; i < entryCount; ++i) + { + array.ArrayPushBack(createEntry(i)); + } + return array; + }; + + auto createObject = [&]() -> Value + { + Value object; + object.SetObject(); + for (int i = 0; i < entryCount; ++i) + { + buffer = AZStd::string::format("Key%i", i); + object.AddMember(AZ::Name(buffer), createArray()); + } + return object; + }; + + root["entries"] = createObject(); + + return root; + } + + void DomTestFixture::SetUp() + { + UnitTest::AllocatorsFixture::SetUp(); + SetUpHarness(); + } + + void DomTestFixture::TearDown() + { + TearDownHarness(); + UnitTest::AllocatorsFixture::TearDown(); + } +} // namespace AZ::Dom::Tests diff --git a/Code/Framework/AzCore/Tests/DOM/DomFixtures.h b/Code/Framework/AzCore/Tests/DOM/DomFixtures.h new file mode 100644 index 0000000000..381eff6b98 --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomFixtures.h @@ -0,0 +1,66 @@ +/* + * 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 +#include +#include + +#define DOM_REGISTER_SERIALIZATION_BENCHMARK(BaseClass, Method) \ + BENCHMARK_REGISTER_F(BaseClass, Method)->Args({ 10, 5 })->Args({ 10, 500 })->Args({ 100, 5 })->Args({ 100, 500 }) +#define DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(BaseClass, Method) \ + DOM_REGISTER_SERIALIZATION_BENCHMARK(BaseClass, Method)->Unit(benchmark::kMillisecond); +#define DOM_REGISTER_SERIALIZATION_BENCHMARK_NS(BaseClass, Method) \ + DOM_REGISTER_SERIALIZATION_BENCHMARK(BaseClass, Method)->Unit(benchmark::kNanosecond); + +namespace AZ::Dom::Tests +{ + class DomTestHarness + { + public: + virtual ~DomTestHarness() = default; + + virtual void SetUpHarness(); + virtual void TearDownHarness(); + }; + + class DomBenchmarkFixture + : public DomTestHarness + , public UnitTest::AllocatorsBenchmarkFixture + { + public: + void SetUp(const ::benchmark::State& st) override; + void SetUp(::benchmark::State& st) override; + void TearDown(::benchmark::State& st) override; + void TearDown(const ::benchmark::State& st) override; + + rapidjson::Document GenerateDomJsonBenchmarkDocument(int64_t entryCount, int64_t stringTemplateLength); + AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength); + Value GenerateDomBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength); + + template + static void TakeAndDiscardWithoutTimingDtor(T&& value, benchmark::State& state) + { + { + T instance = AZStd::move(value); + state.PauseTiming(); + } + state.ResumeTiming(); + } + }; + + class DomTestFixture + : public DomTestHarness + , public UnitTest::AllocatorsFixture + { + public: + void SetUp() override; + void TearDown() override; + }; +} // namespace AZ::Dom::Tests diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp index 8eda110e7b..f84b60af07 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp @@ -16,131 +16,14 @@ #include #include #include +#include -namespace Benchmark +namespace AZ::Dom::Benchmark { - class DomJsonBenchmark : public UnitTest::AllocatorsBenchmarkFixture + class DomJsonBenchmark : public Tests::DomBenchmarkFixture { - public: - void SetUp(const ::benchmark::State& st) override - { - UnitTest::AllocatorsBenchmarkFixture::SetUp(st); - AZ::NameDictionary::Create(); - AZ::AllocatorInstance::Create(); - } - - void SetUp(::benchmark::State& st) override - { - UnitTest::AllocatorsBenchmarkFixture::SetUp(st); - AZ::NameDictionary::Create(); - AZ::AllocatorInstance::Create(); - } - - void TearDown(::benchmark::State& st) override - { - AZ::AllocatorInstance::Destroy(); - AZ::NameDictionary::Destroy(); - UnitTest::AllocatorsBenchmarkFixture::TearDown(st); - } - - void TearDown(const ::benchmark::State& st) override - { - AZ::AllocatorInstance::Destroy(); - AZ::NameDictionary::Destroy(); - UnitTest::AllocatorsBenchmarkFixture::TearDown(st); - } - - rapidjson::Document GenerateDomJsonBenchmarkDocument(int64_t entryCount, int64_t stringTemplateLength) - { - rapidjson::Document document; - document.SetObject(); - - AZStd::string entryTemplate; - while (entryTemplate.size() < static_cast(stringTemplateLength)) - { - entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "; - } - entryTemplate.resize(stringTemplateLength); - AZStd::string buffer; - - auto createString = [&](int n) -> rapidjson::Value - { - buffer = AZStd::string::format("#%i %s", n, entryTemplate.c_str()); - return rapidjson::Value(buffer.data(), static_cast(buffer.size()), document.GetAllocator()); - }; - - auto createEntry = [&](int n) -> rapidjson::Value - { - rapidjson::Value entry(rapidjson::kObjectType); - entry.AddMember("string", createString(n), document.GetAllocator()); - entry.AddMember("int", rapidjson::Value(n), document.GetAllocator()); - entry.AddMember("double", rapidjson::Value(static_cast(n) * 0.5), document.GetAllocator()); - entry.AddMember("bool", rapidjson::Value(n % 2 == 0), document.GetAllocator()); - entry.AddMember("null", rapidjson::Value(rapidjson::kNullType), document.GetAllocator()); - return entry; - }; - - auto createArray = [&]() -> rapidjson::Value - { - rapidjson::Value array; - array.SetArray(); - for (int i = 0; i < entryCount; ++i) - { - array.PushBack(createEntry(i), document.GetAllocator()); - } - return array; - }; - - auto createObject = [&]() -> rapidjson::Value - { - rapidjson::Value object; - object.SetObject(); - for (int i = 0; i < entryCount; ++i) - { - buffer = AZStd::string::format("Key%i", i); - rapidjson::Value key; - key.SetString(buffer.data(), static_cast(buffer.length()), document.GetAllocator()); - object.AddMember(key.Move(), createArray(), document.GetAllocator()); - } - return object; - }; - - document.SetObject(); - document.AddMember("entries", createObject(), document.GetAllocator()); - - return document; - } - - AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) - { - rapidjson::Document document = GenerateDomJsonBenchmarkDocument(entryCount, stringTemplateLength); - - AZStd::string serializedJson; - auto result = AZ::JsonSerializationUtils::WriteJsonString(document, serializedJson); - AZ_Assert(result.IsSuccess(), "Failed to serialize generated JSON"); - return serializedJson; - } - - template - void TakeAndDiscardWithoutTimingDtor(T&& value, benchmark::State& state) - { - { - T instance = AZStd::move(value); - state.PauseTiming(); - } - state.ResumeTiming(); - } }; -// Helper macro for registering JSON benchmarks -#define BENCHMARK_REGISTER_JSON(BaseClass, Method) \ - BENCHMARK_REGISTER_F(BaseClass, Method) \ - ->Args({ 10, 5 }) \ - ->Args({ 10, 500 }) \ - ->Args({ 100, 5 }) \ - ->Args({ 100, 500 }) \ - ->Unit(benchmark::kMillisecond); - BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToRapidjsonInPlace)(benchmark::State& state) { AZ::Dom::JsonBackend backend; @@ -163,7 +46,7 @@ namespace Benchmark state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToRapidjsonInPlace) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToRapidjsonInPlace) BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToAzDomValueInPlace)(benchmark::State& state) { @@ -187,7 +70,7 @@ namespace Benchmark state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToAzDomValueInPlace) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToAzDomValueInPlace) BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToRapidjson)(benchmark::State& state) { @@ -207,7 +90,7 @@ namespace Benchmark state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToRapidjson) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToRapidjson) BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToAzDomValue)(benchmark::State& state) { @@ -227,7 +110,7 @@ namespace Benchmark state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToAzDomValue) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToAzDomValue) BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonDeserializeToRapidjson)(benchmark::State& state) { @@ -243,7 +126,7 @@ namespace Benchmark state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonDeserializeToRapidjson) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonDeserializeToRapidjson) BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonMakeComplexObject)(benchmark::State& state) { @@ -254,7 +137,7 @@ namespace Benchmark state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonMakeComplexObject) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonMakeComplexObject) BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonLookupMemberByString)(benchmark::State& state) { @@ -264,7 +147,9 @@ namespace Benchmark { AZStd::string key(AZStd::string::format("key%" PRId64, i)); keys.push_back(key); - document.AddMember(rapidjson::Value(key.data(), static_cast(key.size()), document.GetAllocator()), rapidjson::Value(i), document.GetAllocator()); + document.AddMember( + rapidjson::Value(key.data(), static_cast(key.size()), document.GetAllocator()), rapidjson::Value(i), + document.GetAllocator()); } for (auto _ : state) @@ -293,7 +178,7 @@ namespace Benchmark state.SetItemsProcessed(state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonDeepCopy) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonDeepCopy) BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonCopyAndMutate)(benchmark::State& state) { @@ -309,9 +194,8 @@ namespace Benchmark state.SetItemsProcessed(state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonCopyAndMutate) + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonCopyAndMutate) -#undef BENCHMARK_REGISTER_JSON -} // namespace Benchmark +} // namespace AZ::Dom::Benchmark #endif // defined(HAVE_BENCHMARK) diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp index c7af6438cf..ff9e378134 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp @@ -13,24 +13,23 @@ #include #include #include +#include namespace AZ::Dom::Tests { - class DomJsonTests : public UnitTest::AllocatorsFixture + class DomJsonTests : public DomTestFixture { public: void SetUp() override { - UnitTest::AllocatorsFixture::SetUp(); - NameDictionary::Create(); + DomTestFixture::SetUp(); m_document = AZStd::make_unique(); } void TearDown() override { m_document.reset(); - NameDictionary::Destroy(); - UnitTest::AllocatorsFixture::TearDown(); + DomTestFixture::TearDown(); } rapidjson::Value CreateString(const AZStd::string& text) diff --git a/Code/Framework/AzCore/Tests/DOM/DomValueBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomValueBenchmarks.cpp index 40b96e148b..69d99eb12b 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomValueBenchmarks.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomValueBenchmarks.cpp @@ -6,111 +6,134 @@ * */ -#include #include +#include #include #include -#include +#include namespace AZ::Dom::Benchmark { - class DomValueBenchmark : public UnitTest::AllocatorsBenchmarkFixture + class DomValueBenchmark : public Tests::DomBenchmarkFixture { - public: - void SetUp(const ::benchmark::State& st) override - { - UnitTest::AllocatorsBenchmarkFixture::SetUp(st); - AZ::NameDictionary::Create(); - AZ::AllocatorInstance::Create(); - } - - void SetUp(::benchmark::State& st) override - { - UnitTest::AllocatorsBenchmarkFixture::SetUp(st); - AZ::NameDictionary::Create(); - AZ::AllocatorInstance::Create(); - } - - void TearDown(::benchmark::State& st) override - { - AZ::AllocatorInstance::Destroy(); - AZ::NameDictionary::Destroy(); - UnitTest::AllocatorsBenchmarkFixture::TearDown(st); - } - - void TearDown(const ::benchmark::State& st) override - { - AZ::AllocatorInstance::Destroy(); - AZ::NameDictionary::Destroy(); - UnitTest::AllocatorsBenchmarkFixture::TearDown(st); - } - - Value GenerateDomBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) - { - Value root(Type::Object); - - AZStd::string entryTemplate; - while (entryTemplate.size() < static_cast(stringTemplateLength)) - { - entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "; - } - entryTemplate.resize(stringTemplateLength); - AZStd::string buffer; - - auto createString = [&](int n) -> Value - { - return Value(AZStd::string::format("#%i %s", n, entryTemplate.c_str()), true); - }; - - auto createEntry = [&](int n) -> Value - { - Value entry(Type::Object); - entry.AddMember("string", createString(n)); - entry.AddMember("int", Value(n)); - entry.AddMember("double", Value(static_cast(n) * 0.5)); - entry.AddMember("bool", Value(n % 2 == 0)); - entry.AddMember("null", Value(Type::Null)); - return entry; - }; - - auto createArray = [&]() -> Value - { - Value array(Type::Array); - for (int i = 0; i < entryCount; ++i) - { - array.ArrayPushBack(createEntry(i)); - } - return array; - }; - - auto createObject = [&]() -> Value - { - Value object; - object.SetObject(); - for (int i = 0; i < entryCount; ++i) - { - buffer = AZStd::string::format("Key%i", i); - object.AddMember(AZ::Name(buffer), createArray()); - } - return object; - }; - - root["entries"] = createObject(); - - return root; - } - - template - void TakeAndDiscardWithoutTimingDtor(T&& value, benchmark::State& state) - { - { - T instance = AZStd::move(value); - state.PauseTiming(); - } - state.ResumeTiming(); - } }; + BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueGetType_UsingVariantIndex)(benchmark::State& state) + { + Value intValue(5); + Value boolValue(true); + Value objValue(Type::Object); + Value nodeValue(Type::Node); + Value arrValue(Type::Array); + Value uintValue(5u); + Value doubleValue(4.0); + Value stringValue("foo", true); + + for (auto _ : state) + { + (intValue.GetType()); + (boolValue.GetType()); + (objValue.GetType()); + (nodeValue.GetType()); + (arrValue.GetType()); + (uintValue.GetType()); + (doubleValue.GetType()); + (stringValue.GetType()); + } + + state.SetItemsProcessed(8 * state.iterations()); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueGetType_UsingVariantIndex); + + BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueGetType_UsingVariantVisit)(benchmark::State& state) + { + Value intValue(5); + Value boolValue(true); + Value objValue(Type::Object); + Value nodeValue(Type::Node); + Value arrValue(Type::Array); + Value uintValue(5u); + Value doubleValue(4.0); + Value stringValue("foo", true); + + auto getTypeViaVisit = [](const Value& value) + { + return AZStd::visit( + [](auto&& value) constexpr -> Type + { + using CurrentType = AZStd::decay_t; + if constexpr (AZStd::is_same_v) + { + return Type::Null; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Int64; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Uint64; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Double; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Bool; + } + else if constexpr (AZStd::is_same_v) + { + return Type::String; + } + else if constexpr (AZStd::is_same_v) + { + return Type::String; + } + else if constexpr (AZStd::is_same_v) + { + return Type::String; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Object; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Array; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Node; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Opaque; + } + else + { + AZ_Assert(false, "AZ::Dom::Value::GetType: m_value has an unexpected type"); + } + }, + value.GetInternalValue()); + }; + + for (auto _ : state) + { + (getTypeViaVisit(intValue)); + (getTypeViaVisit(boolValue)); + (getTypeViaVisit(objValue)); + (getTypeViaVisit(nodeValue)); + (getTypeViaVisit(arrValue)); + (getTypeViaVisit(uintValue)); + (getTypeViaVisit(doubleValue)); + (getTypeViaVisit(stringValue)); + } + + state.SetItemsProcessed(8 * state.iterations()); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueGetType_UsingVariantVisit); + BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueMakeComplexObject)(benchmark::State& state) { for (auto _ : state) @@ -120,12 +143,7 @@ namespace AZ::Dom::Benchmark state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations()); } - BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueMakeComplexObject) - ->Args({ 10, 5 }) - ->Args({ 10, 500 }) - ->Args({ 100, 5 }) - ->Args({ 100, 500 }) - ->Unit(benchmark::kMillisecond); + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomValueBenchmark, AzDomValueMakeComplexObject) BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueShallowCopy)(benchmark::State& state) { @@ -139,12 +157,7 @@ namespace AZ::Dom::Benchmark state.SetItemsProcessed(state.iterations()); } - BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueShallowCopy) - ->Args({ 10, 5 }) - ->Args({ 10, 500 }) - ->Args({ 100, 5 }) - ->Args({ 100, 500 }) - ->Unit(benchmark::kNanosecond); + DOM_REGISTER_SERIALIZATION_BENCHMARK_NS(DomValueBenchmark, AzDomValueShallowCopy) BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueCopyAndMutate)(benchmark::State& state) { @@ -159,12 +172,7 @@ namespace AZ::Dom::Benchmark state.SetItemsProcessed(state.iterations()); } - BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueCopyAndMutate) - ->Args({ 10, 5 }) - ->Args({ 10, 500 }) - ->Args({ 100, 5 }) - ->Args({ 100, 500 }) - ->Unit(benchmark::kNanosecond); + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomValueBenchmark, AzDomValueCopyAndMutate) BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueDeepCopy)(benchmark::State& state) { @@ -178,12 +186,7 @@ namespace AZ::Dom::Benchmark state.SetItemsProcessed(state.iterations()); } - BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueDeepCopy) - ->Args({ 10, 5 }) - ->Args({ 10, 500 }) - ->Args({ 100, 5 }) - ->Args({ 100, 500 }) - ->Unit(benchmark::kMillisecond); + DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomValueBenchmark, AzDomValueDeepCopy) BENCHMARK_DEFINE_F(DomValueBenchmark, LookupMemberByName)(benchmark::State& state) { diff --git a/Code/Framework/AzCore/Tests/DOM/DomValueTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomValueTests.cpp index 10e9f29a44..f39ca4818a 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomValueTests.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomValueTests.cpp @@ -15,26 +15,18 @@ #include #include #include +#include namespace AZ::Dom::Tests { - class DomValueTests : public UnitTest::AllocatorsFixture + class DomValueTests : public DomTestFixture { public: - void SetUp() override - { - UnitTest::AllocatorsFixture::SetUp(); - NameDictionary::Create(); - AZ::AllocatorInstance::Create(); - } - void TearDown() override { m_value = Value(); - AZ::AllocatorInstance::Destroy(); - NameDictionary::Destroy(); - UnitTest::AllocatorsFixture::TearDown(); + DomTestFixture::TearDown(); } void PerformValueChecks() diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index 7be3afb4a9..aee6828b76 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -215,6 +215,8 @@ set(FILES AZStd/Variant.cpp AZStd/VariantSerialization.cpp AZStd/VectorAndArray.cpp + DOM/DomFixtures.cpp + DOM/DomFixtures.h DOM/DomJsonTests.cpp DOM/DomJsonBenchmarks.cpp DOM/DomValueTests.cpp