149 lines
5.8 KiB
C++
149 lines
5.8 KiB
C++
/**
|
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
* SPDX-License-Identifier: Apache-2.0.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <aws/testing/Testing_EXPORTS.h>
|
|
|
|
#include <aws/core/utils/memory/MemorySystemInterface.h>
|
|
#include <aws/core/utils/memory/AWSMemory.h>
|
|
|
|
#include <stdint.h>
|
|
#include <algorithm>
|
|
#include <mutex>
|
|
#include <atomic>
|
|
#include <cstdlib>
|
|
|
|
// 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
|