From 9e1c12636cfb32ac93c836ddd201f032c7a59076 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 3 Feb 2020 19:28:13 +0000 Subject: [PATCH 1/5] Issue with low-memory notification The low-memory notification was getting into an infinite loop. This fixes the loop termination, and provides a test for platforms which support low-memory notification. --- src/mem/largealloc.h | 2 +- src/test/perf/low_memory/low-memory.cc | 127 +++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/test/perf/low_memory/low-memory.cc diff --git a/src/mem/largealloc.h b/src/mem/largealloc.h index 93c5cff..49a0a14 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 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..4bff188 --- /dev/null +++ b/src/test/perf/low_memory/low-memory.cc @@ -0,0 +1,127 @@ +#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 = 1; + size_t i = 0; + while(!has_pressure()) + { + i++; + allocations.add(size); + allocations.try_remove(); + allocations.add(size); + + if (i % 8192 == 0) + size ++; + } +} + +void reduce_pressure(Queue& allocations) +{ + size_t size = 1; + size_t i = 0; + + for (size_t n = 0; n < 1000; n++) + { + allocations.try_remove(); + allocations.try_remove(); + allocations.add(size); + + if (i % 8192 == 0) + size ++; + } +} + + +int main(int, char**) +{ + + Queue allocations; + + + if constexpr (!pal_supports) + { + std::cout << "Pal does not support low-memory notification! Test not run" + << std::endl; + return 0; + } + + setup(); + + for(size_t i = 0; i < 10; i++) + { + reach_pressure(allocations); + std::cout << "Pressure " << i << std::endl; + + reduce_pressure(allocations); + + } + + return 0; +} \ No newline at end of file From a0e6c66af0695212f36ed98fb43678501dfdea11 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Tue, 4 Feb 2020 10:06:52 +0000 Subject: [PATCH 2/5] Remove test from 32bit Windows Windows is only sending low-memory notifications when the machine is reaching low-memory. So running a 32bit process on 64bit machine can easily exhaust address space before machine gets close to low-memory. --- src/test/perf/low_memory/low-memory.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/perf/low_memory/low-memory.cc b/src/test/perf/low_memory/low-memory.cc index 4bff188..3eb84e2 100644 --- a/src/test/perf/low_memory/low-memory.cc +++ b/src/test/perf/low_memory/low-memory.cc @@ -112,6 +112,9 @@ int main(int, char**) 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++) @@ -122,6 +125,6 @@ int main(int, char**) reduce_pressure(allocations); } - +#endif return 0; } \ No newline at end of file From 5d85c203c3f7ab7f166a85e2af402ec1b43e4ce4 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Tue, 4 Feb 2020 13:05:09 +0000 Subject: [PATCH 3/5] Fixes to test for CI. --- src/test/perf/low_memory/low-memory.cc | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/test/perf/low_memory/low-memory.cc b/src/test/perf/low_memory/low-memory.cc index 3eb84e2..02b01aa 100644 --- a/src/test/perf/low_memory/low-memory.cc +++ b/src/test/perf/low_memory/low-memory.cc @@ -68,40 +68,32 @@ bool has_pressure() void reach_pressure(Queue& allocations) { - size_t size = 1; - size_t i = 0; + size_t size = 4096; + while(!has_pressure()) { - i++; allocations.add(size); allocations.try_remove(); allocations.add(size); - - if (i % 8192 == 0) - size ++; + allocations.add(size); } } void reduce_pressure(Queue& allocations) { - size_t size = 1; - size_t i = 0; - + size_t size = 4096; for (size_t n = 0; n < 1000; n++) { allocations.try_remove(); allocations.try_remove(); allocations.add(size); - - if (i % 8192 == 0) - size ++; } } int main(int, char**) { - +#ifndef NDEBUG Queue allocations; @@ -112,9 +104,9 @@ int main(int, char**) return 0; } -#if defined(WIN32) && !defined(SNMALLOC_VA_BITS_64) +# if defined(WIN32) && !defined(SNMALLOC_VA_BITS_64) std::cout << "32-bit windows not supported for this test." << std::endl; -#else +# else setup(); for(size_t i = 0; i < 10; i++) @@ -125,6 +117,9 @@ int main(int, char**) reduce_pressure(allocations); } +# endif +#else + std::cout << "Release test only." << std::endl; #endif return 0; } \ No newline at end of file From 9d6bf750f7abccc8ffd268b3d5569a71586ede0a Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Tue, 4 Feb 2020 13:15:04 +0000 Subject: [PATCH 4/5] Clang format. --- src/test/perf/low_memory/low-memory.cc | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/test/perf/low_memory/low-memory.cc b/src/test/perf/low_memory/low-memory.cc index 02b01aa..240373f 100644 --- a/src/test/perf/low_memory/low-memory.cc +++ b/src/test/perf/low_memory/low-memory.cc @@ -1,10 +1,9 @@ +#include #include #include #include #include - #include -#include using namespace snmalloc; @@ -47,13 +46,12 @@ public: ThreadAlloc::get()->dealloc(head); head = next; } - }; bool has_pressure() { static thread_local uint64_t epoch; - + if constexpr (!pal_supports) { return false; @@ -65,12 +63,11 @@ bool has_pressure() return result; } - void reach_pressure(Queue& allocations) { size_t size = 4096; - while(!has_pressure()) + while (!has_pressure()) { allocations.add(size); allocations.try_remove(); @@ -90,17 +87,15 @@ void reduce_pressure(Queue& allocations) } } - 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; + std::cout << "Pal does not support low-memory notification! Test not run" + << std::endl; return 0; } @@ -109,13 +104,12 @@ int main(int, char**) # else setup(); - for(size_t i = 0; i < 10; i++) + for (size_t i = 0; i < 10; i++) { reach_pressure(allocations); - std::cout << "Pressure " << i << std::endl; + std::cout << "Pressure " << i << std::endl; reduce_pressure(allocations); - } # endif #else From 02427f98f003901768333de3617181b31ea67bd4 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Tue, 4 Feb 2020 14:12:28 +0000 Subject: [PATCH 5/5] Clangformat. --- src/mem/alloc.h | 3 +-- src/mem/largealloc.h | 7 ++++--- src/mem/slab.h | 4 ++-- src/mem/superslab.h | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) 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 49a0a14..4384401 100644 --- a/src/mem/largealloc.h +++ b/src/mem/largealloc.h @@ -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++) {