/* * Copyright (C) 2023 The Android Open Source Project * * 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 * * http://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 "src/trace_processor/util/bump_allocator.h" #include #include #include #include #include #include "test/gtest_and_gmock.h" namespace perfetto::trace_processor { class BumpAllocatorUnittest : public ::testing::Test { public: // Allocates |size| bytes of memory with aligned to |align|, writes |size| // bytes in the region, reads |size| bytes and then frees the memory. // // Very useful to check that none of the internal DCHECKs of the allocator // fire. void AllocateWriteReadAndFree(uint32_t size) { BumpAllocator::AllocId id = allocator_.Alloc(size); uint8_t* ptr = static_cast(allocator_.GetPointer(id)); std::vector data(size); for (uint32_t i = 0; i < size; ++i) { data[i] = static_cast(rnd_engine_() & std::numeric_limits::max()); } memcpy(ptr, data.data(), size); ASSERT_EQ(memcmp(ptr, data.data(), size), 0); allocator_.Free(id); } protected: std::minstd_rand0 rnd_engine_; BumpAllocator allocator_; }; TEST_F(BumpAllocatorUnittest, AllocSmoke) { AllocateWriteReadAndFree(8); AllocateWriteReadAndFree(16); AllocateWriteReadAndFree(24); AllocateWriteReadAndFree(64); AllocateWriteReadAndFree(1024); AllocateWriteReadAndFree(BumpAllocator::kChunkSize); allocator_.EraseFrontFreeChunks(); } TEST_F(BumpAllocatorUnittest, EraseFrontAtAnyTime) { BumpAllocator::AllocId id = allocator_.Alloc(8); allocator_.EraseFrontFreeChunks(); allocator_.Free(id); allocator_.EraseFrontFreeChunks(); } TEST_F(BumpAllocatorUnittest, PastEndOnChunkBoundary) { BumpAllocator::AllocId id = allocator_.Alloc(BumpAllocator::kChunkSize); BumpAllocator::AllocId past_end = allocator_.PastTheEndId(); ASSERT_GT(past_end, id); ASSERT_EQ(past_end.chunk_index, 1u); ASSERT_EQ(past_end.chunk_offset, 0u); allocator_.Free(id); } TEST_F(BumpAllocatorUnittest, EraseFrontAccounting) { AllocateWriteReadAndFree(8); ASSERT_EQ(allocator_.EraseFrontFreeChunks(), 1u); ASSERT_EQ(allocator_.erased_front_chunks_count(), 1u); AllocateWriteReadAndFree(8); ASSERT_EQ(allocator_.EraseFrontFreeChunks(), 1u); ASSERT_EQ(allocator_.erased_front_chunks_count(), 2u); } TEST_F(BumpAllocatorUnittest, EraseFrontFreeChunk) { AllocateWriteReadAndFree(8); allocator_.EraseFrontFreeChunks(); auto past_id = allocator_.PastTheEndId(); ASSERT_EQ(past_id.chunk_index, 1u); ASSERT_EQ(past_id.chunk_offset, 0u); auto id = allocator_.Alloc(8); ASSERT_EQ(id.chunk_index, past_id.chunk_index); ASSERT_EQ(id.chunk_offset, past_id.chunk_offset); allocator_.Free(id); } TEST_F(BumpAllocatorUnittest, StressTest) { std::minstd_rand0 rnd_engine; for (int i = 0; i < 1000; i++) { uint32_t size = static_cast((rnd_engine() * 8) % BumpAllocator::kChunkSize); AllocateWriteReadAndFree(size); } } } // namespace perfetto::trace_processor