blob: 18f09a1a1862bf6f648977c73fa1113a04cd7108 [file] [log] [blame]
// 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<kCapacity>;
using Benchmark =
::pw::allocator::DefaultBlockAllocatorBenchmark<AllocatorForTest>;
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 <typename GetByKey>
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<size_t>& {
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<float>& {
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<size_t>& {
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