Merge pull request #123 from microsoft/low-memory-fix
Issue with low-memory notification
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
119
src/test/perf/low_memory/low-memory.cc
Normal file
119
src/test/perf/low_memory/low-memory.cc
Normal file
@@ -0,0 +1,119 @@
|
||||
#include <iostream>
|
||||
#include <snmalloc.h>
|
||||
#include <test/measuretime.h>
|
||||
#include <test/setup.h>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
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<LowMemoryNotification, GlobalVirtual>)
|
||||
{
|
||||
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<LowMemoryNotification, GlobalVirtual>)
|
||||
{
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user