diff --git a/src/deluge/memory/general_memory_allocator.cpp b/src/deluge/memory/general_memory_allocator.cpp index 90968f1e8b..ba1ea7f4b4 100644 --- a/src/deluge/memory/general_memory_allocator.cpp +++ b/src/deluge/memory/general_memory_allocator.cpp @@ -35,11 +35,12 @@ GeneralMemoryAllocator::GeneralMemoryAllocator() { lock = false; regions[MEMORY_REGION_STEALABLE].setup(emptySpacesMemory, sizeof(emptySpacesMemory), (uint32_t)&__sdram_bss_end, - EXTERNAL_MEMORY_END - RESERVED_EXTERNAL_ALLOCATOR); + EXTERNAL_MEMORY_END - RESERVED_EXTERNAL_ALLOCATOR, &cacheManager); regions[MEMORY_REGION_EXTERNAL].setup(emptySpacesMemoryGeneral, sizeof(emptySpacesMemoryGeneral), - EXTERNAL_MEMORY_END - RESERVED_EXTERNAL_ALLOCATOR, EXTERNAL_MEMORY_END); + EXTERNAL_MEMORY_END - RESERVED_EXTERNAL_ALLOCATOR, EXTERNAL_MEMORY_END, + nullptr); regions[MEMORY_REGION_INTERNAL].setup(emptySpacesMemoryInternal, sizeof(emptySpacesMemoryInternal), - (uint32_t)&__heap_start, (uint32_t)&program_stack_start); + (uint32_t)&__heap_start, (uint32_t)&program_stack_start, nullptr); #if ALPHA_OR_BETA_VERSION regions[MEMORY_REGION_STEALABLE].name = "stealable"; diff --git a/src/deluge/memory/general_memory_allocator.h b/src/deluge/memory/general_memory_allocator.h index 930375c797..6bf3f0fd11 100644 --- a/src/deluge/memory/general_memory_allocator.h +++ b/src/deluge/memory/general_memory_allocator.h @@ -92,7 +92,8 @@ class GeneralMemoryAllocator { void putStealableInAppropriateQueue(Stealable* stealable); MemoryRegion regions[NUM_MEMORY_REGIONS]; - + // only used for managing stealables (audio files that we could deallocate and re load from sd later if needed) + CacheManager cacheManager; bool lock; static GeneralMemoryAllocator& get() { diff --git a/src/deluge/memory/memory_region.cpp b/src/deluge/memory/memory_region.cpp index b801d746a4..13d5f28144 100644 --- a/src/deluge/memory/memory_region.cpp +++ b/src/deluge/memory/memory_region.cpp @@ -28,11 +28,10 @@ #endif MemoryRegion::MemoryRegion() : emptySpaces(sizeof(EmptySpaceRecord)) { - numAllocations = 0; } void MemoryRegion::setup(void* emptySpacesMemory, int32_t emptySpacesMemorySize, uint32_t regionBegin, - uint32_t regionEnd) { + uint32_t regionEnd, CacheManager* cacheManager) { emptySpaces.setStaticMemory(emptySpacesMemory, emptySpacesMemorySize); // bit of a hack - the allocations start with a 4 byte type+size header, this ensures the // resulting allocations are still aligned to 16 bytes (which should generally be fine for anything?) @@ -53,20 +52,20 @@ void MemoryRegion::setup(void* emptySpacesMemory, int32_t emptySpacesMemorySize, EmptySpaceRecord* firstRecord = (EmptySpaceRecord*)emptySpaces.getElementAddress(0); firstRecord->length = memorySizeWithoutHeaders; firstRecord->address = regionBegin + 8; - pivot = 512; + cache_manager_ = cacheManager; } uint32_t MemoryRegion::padSize(uint32_t requiredSize) { requiredSize += 8; // dirty hack - we need the size with its headers to be aligned so we'll add it here then // subtract 8 afterwards - if (requiredSize < minAlign) { - requiredSize = minAlign; + if (requiredSize < minAlign_) { + requiredSize = minAlign_; } else { int extraSize = 0; - while (requiredSize > maxAlign) { - extraSize += maxAlign; - requiredSize -= maxAlign; + while (requiredSize > maxAlign_) { + extraSize += maxAlign_; + requiredSize -= maxAlign_; } // if it's not a power of 2 go up to the next power of 2 if (!((requiredSize & (requiredSize - 1)) == 0)) { @@ -280,7 +279,7 @@ inline void MemoryRegion::markSpaceAsEmpty(uint32_t address, uint32_t spaceSize, void* MemoryRegion::alloc(uint32_t requiredSize, bool makeStealable, void* thingNotToStealFrom) { requiredSize = padSize(requiredSize); - bool large = requiredSize > pivot; + bool large = requiredSize > pivot_; // set a minimum size requiredSize = padSize(requiredSize); int32_t allocatedSize; uint32_t allocatedAddress; @@ -310,7 +309,7 @@ void* MemoryRegion::alloc(uint32_t requiredSize, bool makeStealable, void* thing FREEZE_WITH_ERROR("M003"); } else { - if (extraSpaceSizeWithoutItsHeaders <= minAlign) { + if (extraSpaceSizeWithoutItsHeaders <= minAlign_) { emptySpaces.deleteAtIndex(i); } else { @@ -375,7 +374,7 @@ void* MemoryRegion::alloc(uint32_t requiredSize, bool makeStealable, void* thing // Or if no empty space big enough, try stealing some memory else { noEmptySpace: - allocatedAddress = cache_manager_.ReclaimMemory(*this, requiredSize, thingNotToStealFrom, &allocatedSize); + allocatedAddress = cache_manager_->ReclaimMemory(*this, requiredSize, thingNotToStealFrom, &allocatedSize); if (!allocatedAddress) { #if ALPHA_OR_BETA_VERSION if (name) { @@ -400,7 +399,7 @@ void* MemoryRegion::alloc(uint32_t requiredSize, bool makeStealable, void* thing // See if there was some extra space left over int32_t extraSpaceSizeWithoutItsHeaders = allocatedSize - requiredSize - 8; - if (requiredSize && extraSpaceSizeWithoutItsHeaders > minAlign) { + if (requiredSize && extraSpaceSizeWithoutItsHeaders > minAlign_) { allocatedSize = requiredSize; markSpaceAsEmpty(allocatedAddress + allocatedSize + 8, extraSpaceSizeWithoutItsHeaders, false, false); } diff --git a/src/deluge/memory/memory_region.h b/src/deluge/memory/memory_region.h index 14af79f60d..5b742e3ac2 100644 --- a/src/deluge/memory/memory_region.h +++ b/src/deluge/memory/memory_region.h @@ -20,6 +20,8 @@ #include "memory/cache_manager.h" #include "util/container/array/ordered_resizeable_array_with_multi_word_key.h" +#include + struct EmptySpaceRecord { uint32_t length; uint32_t address; @@ -36,15 +38,16 @@ struct NeighbouringMemoryGrabAttemptResult { #define SPACE_TYPE_MASK 0xC0000000u #define SPACE_SIZE_MASK 0x3FFFFFFFu - -constexpr int32_t maxAlign = 1 << 12; -constexpr int32_t minAlign = 64; - +constexpr size_t max_align_big = 1 << 12; +constexpr size_t min_align_big = 64; +constexpr size_t pivot_big = 512; class MemoryRegion { public: MemoryRegion(); - void setup(void* emptySpacesMemory, int32_t emptySpacesMemorySize, uint32_t regionBegin, uint32_t regionEnd); + void setup(void* emptySpacesMemory, int32_t emptySpacesMemorySize, uint32_t regionBegin, uint32_t regionEnd, + CacheManager* cacheManager); void* alloc(uint32_t requiredSize, bool makeStealable, void* thingNotToStealFrom); + size_t nallocx(size_t size) { return padSize(size); } uint32_t shortenRight(void* address, uint32_t newSize); uint32_t shortenLeft(void* address, uint32_t amountToShorten, uint32_t numBytesToMoveRightIfSuccessful = 0); void extend(void* address, uint32_t minAmountToExtend, uint32_t idealAmountToExtend, @@ -55,9 +58,13 @@ class MemoryRegion { uint32_t start; uint32_t end; - uint32_t numAllocations; - uint32_t pivot; - CacheManager& cache_manager() { return cache_manager_; } + + CacheManager& cache_manager() { + if (cache_manager_) { + return *cache_manager_; + } + throw deluge::exception::NO_CACHE_FOR_REGION; + } #if ALPHA_OR_BETA_VERSION char const* name; // For debugging messages only. @@ -66,8 +73,13 @@ class MemoryRegion { private: friend class CacheManager; - CacheManager cache_manager_; - + // manages "stealables" for a memory region, only used in external stealable region + CacheManager* cache_manager_; + uint32_t numAllocations_{0}; + uint32_t pivot_{pivot_big}; // items smaller than pivot allocate to left, larger to right + size_t maxAlign_ = max_align_big; + // not size_t, it needs to be compared to results of pointer subtractions that can be negative + ptrdiff_t minAlign_ = min_align_big; void markSpaceAsEmpty(uint32_t spaceStart, uint32_t spaceSize, bool mayLookLeft = true, bool mayLookRight = true); NeighbouringMemoryGrabAttemptResult attemptToGrabNeighbouringMemory(void* originalSpaceAddress, int32_t originalSpaceSize, int32_t minAmountToExtend, diff --git a/src/deluge/util/exceptions.h b/src/deluge/util/exceptions.h index dd81193bc3..a76dfcd1cc 100644 --- a/src/deluge/util/exceptions.h +++ b/src/deluge/util/exceptions.h @@ -4,5 +4,6 @@ namespace deluge { enum class exception { BAD_ALLOC, BAD_RELEASE, + NO_CACHE_FOR_REGION, }; } diff --git a/tests/32bit_unit_tests/memory_tests.cpp b/tests/32bit_unit_tests/memory_tests.cpp index 26e97aa67f..8ad145a4bc 100644 --- a/tests/32bit_unit_tests/memory_tests.cpp +++ b/tests/32bit_unit_tests/memory_tests.cpp @@ -84,6 +84,7 @@ bool testAllocationStructure(void* address, uint32_t size, uint32_t spaceType) { TEST_GROUP(MemoryAllocation) { MemoryRegion memreg; + CacheManager cm; // this will hold the address of the stealable test vtable uint32_t empty_spaze_size = sizeof(EmptySpaceRecord) * 512; void* emptySpacesMemory = malloc(empty_spaze_size); @@ -92,9 +93,10 @@ TEST_GROUP(MemoryAllocation) { // this runs before each test to re intitialize the memory void setup() { nSteals = 0; + auto newCM = new (&cm) CacheManager(); memset(raw_mem, 0, mem_size); memset(emptySpacesMemory, 0, empty_spaze_size); - memreg.setup(emptySpacesMemory, empty_spaze_size, (uint32_t)raw_mem, (uint32_t)raw_mem + mem_size); + memreg.setup(emptySpacesMemory, empty_spaze_size, (uint32_t)raw_mem, (uint32_t)raw_mem + mem_size, newCM); } }; @@ -319,6 +321,7 @@ TEST(MemoryAllocation, stealableAllocations) { void* testalloc = memreg.alloc(size, true, NULL); totalAllocated += size; StealableTest* stealable = new (testalloc) StealableTest(); + memreg.cache_manager().QueueForReclamation(StealableQueue{0}, stealable); vtableAddress = *(uint32_t*)testalloc; actualSize = getAllocatedSize(testalloc);