diff --git a/src/mem/alloc.h b/src/mem/alloc.h index 8d1ae12..76434e6 100644 --- a/src/mem/alloc.h +++ b/src/mem/alloc.h @@ -1070,8 +1070,7 @@ namespace snmalloc bool was_full = super->is_full(); SlabList* sl = &small_classes[sizeclass]; Slab* slab = Metaslab::get_slab(p); - Superslab::Action a = - slab->dealloc_slow(sl, super, p); + Superslab::Action a = slab->dealloc_slow(sl, super, p); if (likely(a == Superslab::NoSlabReturn)) return; stats().sizeclass_dealloc_slab(sizeclass); diff --git a/src/mem/largealloc.h b/src/mem/largealloc.h index 93c5cff..4384401 100644 --- a/src/mem/largealloc.h +++ b/src/mem/largealloc.h @@ -263,7 +263,7 @@ namespace snmalloc { lazy_decommit(); } - } while (old_epoch <= new_epoch); + } while (old_epoch < new_epoch); } } #endif @@ -403,13 +403,14 @@ namespace snmalloc } // Cross-reference largealloc's alloc() decommitted condition. - if ((decommit_strategy != DecommitNone) - && (large_class != 0 || decommit_strategy == DecommitSuper)) + if ( + (decommit_strategy != DecommitNone) && + (large_class != 0 || decommit_strategy == DecommitSuper)) { size_t rsize = bits::one_at_bit(SUPERSLAB_BITS) << large_class; memory_provider.notify_not_using( - pointer_offset(p, OS_PAGE_SIZE), rsize - OS_PAGE_SIZE); + pointer_offset(p, OS_PAGE_SIZE), rsize - OS_PAGE_SIZE); } stats.superslab_push(); diff --git a/src/mem/slab.h b/src/mem/slab.h index ce71f76..00058ae 100644 --- a/src/mem/slab.h +++ b/src/mem/slab.h @@ -178,8 +178,8 @@ namespace snmalloc // This does not need to remove the "use" as done by the fast path. // Returns a complex return code for managing the superslab meta data. // i.e. This deallocation could make an entire superslab free. - SNMALLOC_SLOW_PATH typename Superslab::Action dealloc_slow( - SlabList* sl, Superslab* super, void* p) + SNMALLOC_SLOW_PATH typename Superslab::Action + dealloc_slow(SlabList* sl, Superslab* super, void* p) { Metaslab& meta = super->get_meta(this); diff --git a/src/mem/superslab.h b/src/mem/superslab.h index b0a036a..8e3a7fc 100644 --- a/src/mem/superslab.h +++ b/src/mem/superslab.h @@ -84,7 +84,7 @@ namespace snmalloc { if (kind != Fresh) { - // If this wasn't previously Fresh, we need to zero some things. + // If this wasn't previously Fresh, we need to zero some things. used = 0; for (size_t i = 0; i < SLAB_COUNT; i++) { @@ -105,7 +105,8 @@ namespace snmalloc { curr = (curr + meta[curr].next + 1) & (SLAB_COUNT - 1); } - if (curr != 0) abort(); + if (curr != 0) + abort(); for (size_t i = 0; i < SLAB_COUNT; i++) { diff --git a/src/test/perf/low_memory/low-memory.cc b/src/test/perf/low_memory/low-memory.cc new file mode 100644 index 0000000..240373f --- /dev/null +++ b/src/test/perf/low_memory/low-memory.cc @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include + +using namespace snmalloc; + +struct Node +{ + Node* next; +}; + +class Queue +{ + Node* head; + Node* tail; + + Node* new_node(size_t size) + { + auto result = (Node*)ThreadAlloc::get()->alloc(size); + result->next = nullptr; + return result; + } + +public: + Queue() + { + head = new_node(1); + tail = head; + } + + void add(size_t size) + { + tail->next = new_node(size); + tail = tail->next; + } + + void try_remove() + { + if (head->next == nullptr) + return; + + Node* next = head->next; + ThreadAlloc::get()->dealloc(head); + head = next; + } +}; + +bool has_pressure() +{ + static thread_local uint64_t epoch; + + if constexpr (!pal_supports) + { + return false; + } + + uint64_t current_epoch = default_memory_provider.low_memory_epoch(); + bool result = epoch != current_epoch; + epoch = current_epoch; + return result; +} + +void reach_pressure(Queue& allocations) +{ + size_t size = 4096; + + while (!has_pressure()) + { + allocations.add(size); + allocations.try_remove(); + allocations.add(size); + allocations.add(size); + } +} + +void reduce_pressure(Queue& allocations) +{ + size_t size = 4096; + for (size_t n = 0; n < 1000; n++) + { + allocations.try_remove(); + allocations.try_remove(); + allocations.add(size); + } +} + +int main(int, char**) +{ +#ifndef NDEBUG + Queue allocations; + + if constexpr (!pal_supports) + { + std::cout << "Pal does not support low-memory notification! Test not run" + << std::endl; + return 0; + } + +# if defined(WIN32) && !defined(SNMALLOC_VA_BITS_64) + std::cout << "32-bit windows not supported for this test." << std::endl; +# else + setup(); + + for (size_t i = 0; i < 10; i++) + { + reach_pressure(allocations); + std::cout << "Pressure " << i << std::endl; + + reduce_pressure(allocations); + } +# endif +#else + std::cout << "Release test only." << std::endl; +#endif + return 0; +} \ No newline at end of file