SurfaceTagWeights optimization (#7436)

* Add comparison operators to SurfaceTagWeight.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Changed AddSurfaceTagWeight to always combine weights.
This simplifies the API a bit and defines the behavior if someone ever tries to add a duplicate tag.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Added benchmarks for measuring the performance-critical APIs.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Changed SurfaceTagWeights to a fixed_vector.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2022-02-07 10:57:39 -06:00
committed by GitHub
parent 58f8cc666c
commit a6ddf4164f
9 changed files with 198 additions and 61 deletions
@@ -12,6 +12,7 @@
#include <AzCore/Component/Entity.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/Math/Random.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/std/containers/array.h>
#include <AzCore/std/containers/span.h>
@@ -270,6 +271,88 @@ namespace UnitTest
->Arg( 2048 )
->Unit(::benchmark::kMillisecond);
BENCHMARK_DEFINE_F(SurfaceDataBenchmark, BM_AddSurfaceTagWeight)(benchmark::State& state)
{
AZ_PROFILE_FUNCTION(Entity);
AZ::Crc32 tags[SurfaceData::SurfaceTagWeights::MaxSurfaceWeights];
AZ::SimpleLcgRandom randomGenerator(1234567);
// Declare this outside the loop so that we aren't benchmarking creation and destruction.
SurfaceData::SurfaceTagWeights weights;
bool clearEachTime = state.range(0) > 0;
// Create a list of randomly-generated tag values.
for (auto& tag : tags)
{
tag = randomGenerator.GetRandom();
}
for (auto _ : state)
{
// We'll benchmark this two ways:
// 1. We clear each time, which means each AddSurfaceWeightIfGreater call will search the whole list then add.
// 2. We don't clear, which means that after the first run, AddSurfaceWeightIfGreater will always try to replace values.
if (clearEachTime)
{
weights.Clear();
}
// For each tag, try to add it with a random weight.
for (auto& tag : tags)
{
weights.AddSurfaceTagWeight(tag, randomGenerator.GetRandomFloat());
}
}
}
BENCHMARK_REGISTER_F(SurfaceDataBenchmark, BM_AddSurfaceTagWeight)
->Arg(false)
->Arg(true)
->ArgName("ClearEachTime");
BENCHMARK_DEFINE_F(SurfaceDataBenchmark, BM_HasAnyMatchingTags_NoMatches)(benchmark::State& state)
{
AZ_PROFILE_FUNCTION(Entity);
AZ::Crc32 tags[SurfaceData::SurfaceTagWeights::MaxSurfaceWeights];
AZ::SimpleLcgRandom randomGenerator(1234567);
// Declare this outside the loop so that we aren't benchmarking creation and destruction.
SurfaceData::SurfaceTagWeights weights;
// Create a list of randomly-generated tag values.
for (auto& tag : tags)
{
// Specifically always set the last bit so that we can create comparison tags that won't match.
tag = randomGenerator.GetRandom() | 0x01;
// Add the tag to our weights list with a random weight.
weights.AddSurfaceTagWeight(tag, randomGenerator.GetRandomFloat());
}
// Create a set of similar comparison tags that won't match. We still want a random distribution of values though,
// because the SurfaceTagWeights might behave differently with ordered lists.
SurfaceData::SurfaceTagVector comparisonTags;
for (auto& tag : tags)
{
comparisonTags.emplace_back(tag ^ 0x01);
}
for (auto _ : state)
{
// Test to see if any of our tags match.
// All of comparison tags should get compared against all of the added tags.
bool result = weights.HasAnyMatchingTags(comparisonTags);
benchmark::DoNotOptimize(result);
}
}
BENCHMARK_REGISTER_F(SurfaceDataBenchmark, BM_HasAnyMatchingTags_NoMatches);
#endif
}