// Copyright 2024 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_allocator/benchmarks/benchmark.h" #include "public/pw_allocator/benchmarks/measurements.h" #include "pw_allocator/benchmarks/measurements.h" #include "pw_allocator/fragmentation.h" #include "pw_allocator/test_harness.h" #include "pw_allocator/testing.h" #include "pw_random/xor_shift.h" #include "pw_unit_test/framework.h" namespace { constexpr size_t kCapacity = 65536; constexpr size_t kMaxSize = 64; using AllocatorForTest = ::pw::allocator::test::AllocatorForTest; using Benchmark = ::pw::allocator::DefaultBlockAllocatorBenchmark; using ::pw::allocator::CalculateFragmentation; using ::pw::allocator::Measurement; using ::pw::allocator::Measurements; using ::pw::allocator::test::AllocationRequest; using ::pw::allocator::test::kToken; using ::pw::allocator::test::Request; template bool IsChanged(Benchmark& benchmark, GetByKey get_by_key) { return get_by_key(benchmark.measurements()).count() != 0; } bool ByCountChanged(Benchmark& benchmark, size_t count) { return IsChanged(benchmark, [count](Measurements& m) -> Measurement& { return m.GetByCount(count); }); } TEST(BenchmarkTest, ByCount) { AllocatorForTest allocator; Benchmark benchmark(kToken, allocator); benchmark.set_prng_seed(1); benchmark.set_available(kCapacity); EXPECT_FALSE(ByCountChanged(benchmark, 0)); benchmark.GenerateRequest(kMaxSize); EXPECT_TRUE(ByCountChanged(benchmark, 0)); while (benchmark.num_allocations() < 9) { benchmark.GenerateRequest(kMaxSize); } EXPECT_FALSE(ByCountChanged(benchmark, 10)); while (benchmark.num_allocations() < 10) { benchmark.GenerateRequest(kMaxSize); } EXPECT_TRUE(ByCountChanged(benchmark, 10)); while (benchmark.num_allocations() < 99) { benchmark.GenerateRequest(kMaxSize); } EXPECT_FALSE(ByCountChanged(benchmark, 100)); while (benchmark.num_allocations() < 100) { benchmark.GenerateRequest(kMaxSize); } EXPECT_TRUE(ByCountChanged(benchmark, 100)); while (benchmark.num_allocations() < 999) { benchmark.GenerateRequest(kMaxSize); } EXPECT_FALSE(ByCountChanged(benchmark, 1000)); while (benchmark.num_allocations() < 1000) { benchmark.GenerateRequest(kMaxSize); } EXPECT_TRUE(ByCountChanged(benchmark, 1000)); } size_t ByFragmentationChanged(Benchmark& benchmark, float fragmentation) { return IsChanged(benchmark, [fragmentation](Measurements& m) -> Measurement& { return m.GetByFragmentation(fragmentation); }); } TEST(BenchmarkTest, ByFragmentation) { AllocatorForTest allocator; Benchmark benchmark(kToken, allocator); benchmark.set_prng_seed(1); benchmark.set_available(kCapacity); EXPECT_FALSE(ByFragmentationChanged(benchmark, 0.2f)); while (CalculateFragmentation(allocator.MeasureFragmentation()) < 0.2f) { benchmark.GenerateRequest(kMaxSize); } EXPECT_TRUE(ByFragmentationChanged(benchmark, 0.2f)); while (CalculateFragmentation(allocator.MeasureFragmentation()) < 0.4f) { benchmark.GenerateRequest(kMaxSize); } EXPECT_TRUE(ByFragmentationChanged(benchmark, 0.4f)); while (CalculateFragmentation(allocator.MeasureFragmentation()) < 0.6f) { benchmark.GenerateRequest(kMaxSize); } EXPECT_TRUE(ByFragmentationChanged(benchmark, 0.6f)); while (CalculateFragmentation(allocator.MeasureFragmentation()) < 0.8f) { benchmark.GenerateRequest(kMaxSize); } EXPECT_TRUE(ByFragmentationChanged(benchmark, 0.8f)); } bool BySizeChanged(Benchmark& benchmark, size_t size) { return IsChanged(benchmark, [size](Measurements& m) -> Measurement& { return m.GetBySize(size); }); } TEST(BenchmarkTest, BySize) { AllocatorForTest allocator; Benchmark benchmark(kToken, allocator); benchmark.set_prng_seed(1); benchmark.set_available(kCapacity); AllocationRequest request; EXPECT_FALSE(BySizeChanged(benchmark, 4096)); request.size = 8192; EXPECT_TRUE(benchmark.HandleRequest(request)); EXPECT_TRUE(BySizeChanged(benchmark, 4096)); EXPECT_FALSE(BySizeChanged(benchmark, 4095)); EXPECT_FALSE(BySizeChanged(benchmark, 1024)); request.size = 4095; EXPECT_TRUE(benchmark.HandleRequest(request)); EXPECT_TRUE(BySizeChanged(benchmark, 1024)); EXPECT_FALSE(BySizeChanged(benchmark, 1023)); EXPECT_FALSE(BySizeChanged(benchmark, 256)); request.size = 256; EXPECT_TRUE(benchmark.HandleRequest(request)); EXPECT_TRUE(BySizeChanged(benchmark, 256)); EXPECT_FALSE(BySizeChanged(benchmark, 255)); EXPECT_FALSE(BySizeChanged(benchmark, 64)); request.size = 96; EXPECT_TRUE(benchmark.HandleRequest(request)); EXPECT_TRUE(BySizeChanged(benchmark, 64)); EXPECT_FALSE(BySizeChanged(benchmark, 63)); EXPECT_FALSE(BySizeChanged(benchmark, 16)); request.size = 63; EXPECT_TRUE(benchmark.HandleRequest(request)); EXPECT_TRUE(BySizeChanged(benchmark, 16)); EXPECT_FALSE(BySizeChanged(benchmark, 15)); } } // namespace