/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #pragma once #include #include #include #include #include #include #include #include // Could be folded into ExactTestMemorySystem, tracks some aggregate stats class AWS_TESTING_API BaseTestMemorySystem : public Aws::Utils::Memory::MemorySystemInterface { public: BaseTestMemorySystem(); virtual ~BaseTestMemorySystem() {} virtual void Begin() override{} virtual void End() override {} virtual void* AllocateMemory(std::size_t blockSize, std::size_t alignment, const char *allocationTag = nullptr) override; virtual void FreeMemory(void* memoryPtr) override; uint64_t GetCurrentOutstandingAllocations() const { return m_currentOutstandingAllocations; } uint64_t GetMaxOutstandingAllocations() const { return m_maxOutstandingAllocations; } uint64_t GetTotalAllocationCount() const { return m_totalAllocations; } uint64_t GetCurrentBytesAllocated() const { return m_currentBytesAllocated; } uint64_t GetMaxBytesAllocated() const { return m_maxBytesAllocated; } uint64_t GetTotalBytesAllocated() const { return m_totalBytesAllocated; } private: uint64_t m_currentBytesAllocated; uint64_t m_maxBytesAllocated; uint64_t m_totalBytesAllocated; uint64_t m_currentOutstandingAllocations; uint64_t m_maxOutstandingAllocations; uint64_t m_totalAllocations; }; // This is thread-safe; while active it keeps a record of every single allocation made via the memory system allowing us to verify matching deallocations class AWS_TESTING_API ExactTestMemorySystem : public BaseTestMemorySystem { public: typedef BaseTestMemorySystem Base; ExactTestMemorySystem(uint32_t bucketCount, uint32_t trackersPerBlock); virtual ~ExactTestMemorySystem(); virtual void* AllocateMemory(std::size_t blockSize, std::size_t alignment, const char *allocationTag = nullptr) override; virtual void FreeMemory(void* memoryPtr) override; bool IsClean() const; private: // C-style memory tracking // This is the element of internal allocation, containing one or more TaggedMemoryTrackers (# based on m_trackersPerBlock) // This allows us to scale the tracker to tests that do a lot of allocation without having one malloc per TaggedMemoryTracker // POD struct RawBlock { RawBlock* m_next; }; // TaggedMemoryTrackers are ultimately just offsets inside RawBlocks // POD struct TaggedMemoryTracker { TaggedMemoryTracker* m_next; size_t m_size; const char* m_tag; const void* m_memory; }; uint32_t CalculateBucketIndex(const void* memory) const; TaggedMemoryTracker* AllocateTracker(); void GrowFreePool(); void Cleanup(); uint32_t m_bucketCount; uint32_t m_trackersPerBlock; // A linked list of all malloc'd RawBlocks; this is what we free during cleanup RawBlock* m_blocks; // A linked list of available TaggedMemoryTrackers TaggedMemoryTracker* m_freePool; // An array of linked lists of TaggedMemoryTrackers; tracks all allocations made while this system is active; the array size is controlled by m_bucketCount TaggedMemoryTracker** m_buckets; // Keeps allocation/deallocation synchronous so that all of our bookkeeping actually works properly std::mutex m_internalSync; }; #ifdef USE_AWS_MEMORY_MANAGEMENT // Utility macros to put at the start and end of tests // Checks: // (1) Everything allocated by the AWS memory system is deallocated // Macros that can be used to bracket the inside of a gtest body #define AWS_BEGIN_MEMORY_TEST(x, y) ExactTestMemorySystem memorySystem(x, y); \ Aws::Utils::Memory::InitializeAWSMemorySystem(memorySystem); \ { #define AWS_END_MEMORY_TEST } \ Aws::Utils::Memory::ShutdownAWSMemorySystem(); \ ASSERT_EQ(memorySystem.GetCurrentOutstandingAllocations(), 0ULL); \ ASSERT_EQ(memorySystem.GetCurrentBytesAllocated(), 0ULL); \ ASSERT_TRUE(memorySystem.IsClean()); #define AWS_END_MEMORY_OVERRIDE } \ Aws::Utils::Memory::ShutdownAWSMemorySystem(); #define AWS_BEGIN_MEMORY_TEST_EX(options, x, y) ExactTestMemorySystem memorySystem(x, y); \ options.memoryManagementOptions.memoryManager = &memorySystem; #define AWS_END_MEMORY_TEST_EX EXPECT_EQ(memorySystem.GetCurrentOutstandingAllocations(), 0ULL); \ EXPECT_EQ(memorySystem.GetCurrentBytesAllocated(), 0ULL); \ EXPECT_TRUE(memorySystem.IsClean()); \ if (memorySystem.GetCurrentOutstandingAllocations() != 0ULL) return 1; \ if (memorySystem.GetCurrentBytesAllocated() != 0ULL) return 1; \ if (!memorySystem.IsClean()) return 1; #else #define AWS_BEGIN_MEMORY_TEST(x, y) #define AWS_END_MEMORY_TEST #define AWS_END_MEMORY_OVERRIDE #define AWS_BEGIN_MEMORY_TEST_EX(options, x, y) #define AWS_END_MEMORY_TEST_EX #endif // USE_AWS_MEMORY_MANAGEMENT