Add benchmarks, some light optimizations like SSO

Signed-off-by: Nicholas Van Sickle <nvsickle@amazon.com>
This commit is contained in:
Nicholas Van Sickle
2021-12-10 15:57:52 -08:00
parent 947951b6c7
commit 1af39a5c5c
10 changed files with 319 additions and 40 deletions
@@ -8,9 +8,10 @@
#if defined(HAVE_BENCHMARK)
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/DOM/Backends/JSON/JsonBackend.h>
#include <AzCore/DOM/Backends/JSON/JsonSerializationUtils.h>
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/DOM/DomValue.h>
#include <AzCore/JSON/document.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
@@ -25,22 +26,26 @@ namespace Benchmark
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
AZ::NameDictionary::Create();
AZ::AllocatorInstance<AZ::Dom::ValueAllocator>::Create();
}
void SetUp(::benchmark::State& st) override
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
AZ::NameDictionary::Create();
AZ::AllocatorInstance<AZ::Dom::ValueAllocator>::Create();
}
void TearDown(::benchmark::State& st) override
{
AZ::AllocatorInstance<AZ::Dom::ValueAllocator>::Destroy();
AZ::NameDictionary::Destroy();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
void TearDown(const ::benchmark::State& st) override
{
AZ::AllocatorInstance<AZ::Dom::ValueAllocator>::Destroy();
AZ::NameDictionary::Destroy();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
@@ -143,6 +148,30 @@ namespace Benchmark
}
BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDocumentInPlace)
BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDomValueInPlace)(benchmark::State& state)
{
AZ::Dom::JsonBackend backend;
AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1));
for (auto _ : state)
{
state.PauseTiming();
AZStd::string payloadCopy = serializedPayload;
state.ResumeTiming();
auto result = AZ::Dom::Utils::WriteToValue(
[&](AZ::Dom::Visitor& visitor)
{
return AZ::Dom::Utils::ReadFromStringInPlace(backend, payloadCopy, visitor);
});
benchmark::DoNotOptimize(result.GetValue());
}
state.SetBytesProcessed(serializedPayload.size() * state.iterations());
}
BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDomValueInPlace)
BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocument)(benchmark::State& state)
{
AZ::Dom::JsonBackend backend;
@@ -179,6 +208,17 @@ namespace Benchmark
}
BENCHMARK_REGISTER_JSON(DomJsonBenchmark, JsonUtilsDeserializeToDocument)
BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonPayloadGeneration)(benchmark::State& state)
{
for (auto _ : state)
{
benchmark::DoNotOptimize(GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)));
}
state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations());
}
BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonPayloadGeneration)
#undef BENCHMARK_REGISTER_JSON
} // namespace Benchmark
@@ -0,0 +1,117 @@
/*
* 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/DOM/DomValue.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/UnitTest/TestTypes.h>
namespace AZ::Dom::Benchmark
{
class DomValueBenchmark : public UnitTest::AllocatorsBenchmarkFixture
{
public:
void SetUp(const ::benchmark::State& st) override
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
AZ::NameDictionary::Create();
AZ::AllocatorInstance<ValueAllocator>::Create();
}
void SetUp(::benchmark::State& st) override
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
AZ::NameDictionary::Create();
AZ::AllocatorInstance<ValueAllocator>::Create();
}
void TearDown(::benchmark::State& st) override
{
AZ::AllocatorInstance<ValueAllocator>::Destroy();
AZ::NameDictionary::Destroy();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
void TearDown(const ::benchmark::State& st) override
{
AZ::AllocatorInstance<ValueAllocator>::Destroy();
AZ::NameDictionary::Destroy();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
Value GenerateDomBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength)
{
Value root(Type::ObjectType);
AZStd::string entryTemplate;
while (entryTemplate.size() < static_cast<size_t>(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::ObjectType);
entry.AddMember("string", createString(n));
entry.AddMember("int", n);
entry.AddMember("double", static_cast<double>(n) * 0.5);
entry.AddMember("bool", n % 2 == 0);
entry.AddMember("null", Value(Type::NullType));
return entry;
};
auto createArray = [&]() -> Value
{
Value array(Type::ArrayType);
for (int i = 0; i < entryCount; ++i)
{
array.PushBack(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;
}
};
BENCHMARK_DEFINE_F(DomValueBenchmark, ValuePayloadGeneration)(benchmark::State& state)
{
for (auto _ : state)
{
benchmark::DoNotOptimize(GenerateDomBenchmarkPayload(state.range(0), state.range(1)));
}
state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations());
}
BENCHMARK_REGISTER_F(DomValueBenchmark, ValuePayloadGeneration)
->Args({ 10, 5 })
->Args({ 10, 500 })
->Args({ 100, 5 })
->Args({ 100, 500 })
->Unit(benchmark::kMillisecond);
} // namespace AZ::Dom::Benchmark
@@ -25,12 +25,14 @@ namespace AZ::Dom::Tests
{
UnitTest::AllocatorsFixture::SetUp();
NameDictionary::Create();
AZ::AllocatorInstance<ValueAllocator>::Create();
}
void TearDown() override
{
m_value = Value();
AZ::AllocatorInstance<ValueAllocator>::Destroy();
NameDictionary::Destroy();
UnitTest::AllocatorsFixture::TearDown();
}
@@ -279,19 +281,24 @@ namespace AZ::Dom::Tests
TEST_F(DomValueTests, String)
{
const char* s1 = "reference string long enough to avoid SSO";
const char* s2 = "copy string long enough to avoid SSO";
m_value.SetObject();
AZStd::string stringToReference = "foo";
AZStd::string stringToReference = s1;
m_value["no_copy"] = Value(stringToReference, false);
AZStd::string stringToCopy = "bar";
AZStd::string stringToCopy = s2;
m_value["copy"] = Value(stringToCopy, true);
EXPECT_EQ(m_value["no_copy"].GetType(), Type::StringType);
EXPECT_EQ(m_value["no_copy"].GetString(), stringToReference);
EXPECT_EQ(m_value["no_copy"].GetString().data(), stringToReference.data());
EXPECT_EQ(m_value["no_copy"].GetString(), s1);
stringToReference.at(0) = 'F';
EXPECT_NE(m_value["no_copy"].GetString(), s1);
EXPECT_EQ(m_value["copy"].GetType(), Type::StringType);
EXPECT_EQ(m_value["copy"].GetString(), stringToCopy);
EXPECT_NE(m_value["copy"].GetString().data(), stringToCopy.data());
EXPECT_EQ(m_value["copy"].GetString(), s2);
stringToCopy.at(0) = 'F';
EXPECT_EQ(m_value["copy"].GetString(), s2);
PerformValueChecks();
}