// Copyright 2023 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/allocator_metric_proxy.h" #include "gtest/gtest.h" #include "pw_allocator/allocator_testing.h" namespace pw::allocator { namespace { // Test fixtures. class AllocatorMetricProxyTest : public ::testing::Test { protected: AllocatorMetricProxyTest() : allocator(0) {} void SetUp() override { allocator.Initialize(*wrapped); } AllocatorMetricProxy allocator; private: test::AllocatorForTestWithBuffer<256> wrapped; }; // Unit tests. TEST_F(AllocatorMetricProxyTest, InitiallyZero) { EXPECT_EQ(allocator.used(), 0U); EXPECT_EQ(allocator.peak(), 0U); EXPECT_EQ(allocator.count(), 0U); } TEST_F(AllocatorMetricProxyTest, MetricsInitialized) { auto& memusage = allocator.memusage(); EXPECT_EQ(memusage.metrics().size(), 3U); EXPECT_EQ(memusage.children().size(), 0U); } TEST_F(AllocatorMetricProxyTest, AllocateDeallocate) { constexpr Layout layout = Layout::Of(); void* ptr = allocator.Allocate(layout); ASSERT_NE(ptr, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.count(), 1U); allocator.Deallocate(ptr, layout); EXPECT_EQ(allocator.used(), 0U); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.count(), 0U); } TEST_F(AllocatorMetricProxyTest, AllocateFailure) { constexpr Layout layout = Layout::Of(); void* ptr = allocator.Allocate(layout); EXPECT_EQ(ptr, nullptr); EXPECT_EQ(allocator.used(), 0U); EXPECT_EQ(allocator.peak(), 0U); EXPECT_EQ(allocator.count(), 0U); } TEST_F(AllocatorMetricProxyTest, AllocateDeallocateMultiple) { constexpr Layout layout1 = Layout::Of(); void* ptr1 = allocator.Allocate(layout1); ASSERT_NE(ptr1, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 3); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 3); EXPECT_EQ(allocator.count(), 1U); constexpr Layout layout2 = Layout::Of(); void* ptr2 = allocator.Allocate(layout2); ASSERT_NE(ptr2, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 5); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 5); EXPECT_EQ(allocator.count(), 2U); allocator.Deallocate(ptr1, layout1); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 5); EXPECT_EQ(allocator.count(), 1U); allocator.Deallocate(ptr2, layout2); EXPECT_EQ(allocator.used(), 0U); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 5); EXPECT_EQ(allocator.count(), 0U); } TEST_F(AllocatorMetricProxyTest, ResizeLarger) { constexpr Layout old_layout = Layout::Of(); void* ptr = allocator.Allocate(old_layout); ASSERT_NE(ptr, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 3); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 3); EXPECT_EQ(allocator.count(), 1U); constexpr Layout new_layout = Layout::Of(); EXPECT_TRUE(allocator.Resize(ptr, old_layout, new_layout.size())); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 5); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 5); EXPECT_EQ(allocator.count(), 1U); allocator.Deallocate(ptr, new_layout); EXPECT_EQ(allocator.used(), 0U); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 5); EXPECT_EQ(allocator.count(), 0U); } TEST_F(AllocatorMetricProxyTest, ResizeSmaller) { constexpr Layout old_layout = Layout::Of(); void* ptr = allocator.Allocate(old_layout); ASSERT_NE(ptr, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.count(), 1U); constexpr Layout new_layout = Layout::Of(); EXPECT_TRUE(allocator.Resize(ptr, old_layout, new_layout.size())); EXPECT_EQ(allocator.used(), sizeof(uint32_t)); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.count(), 1U); allocator.Deallocate(ptr, new_layout); EXPECT_EQ(allocator.used(), 0U); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.count(), 0U); } TEST_F(AllocatorMetricProxyTest, Reallocate) { constexpr Layout old_layout = Layout::Of(); void* ptr1 = allocator.Allocate(old_layout); ASSERT_NE(ptr1, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.count(), 1U); // Make a second allocation to force reallocation. void* ptr2 = allocator.Allocate(old_layout); ASSERT_NE(ptr2, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 4); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 4); EXPECT_EQ(allocator.count(), 2U); // Reallocating allocates before deallocating, leading to higher peaks. constexpr Layout new_layout = Layout::Of(); void* new_ptr = allocator.Reallocate(ptr1, old_layout, new_layout.size()); EXPECT_NE(new_ptr, nullptr); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 6); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 8); EXPECT_EQ(allocator.count(), 2U); allocator.Deallocate(new_ptr, new_layout); EXPECT_EQ(allocator.used(), sizeof(uint32_t) * 2); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 8); EXPECT_EQ(allocator.count(), 1U); allocator.Deallocate(ptr2, old_layout); EXPECT_EQ(allocator.used(), 0U); EXPECT_EQ(allocator.peak(), sizeof(uint32_t) * 8); EXPECT_EQ(allocator.count(), 0U); } } // namespace } // namespace pw::allocator