Files
snmalloc/src/test/perf/external_pointer/externalpointer.cc
David Chisnall cd70a7856b Fix fallout from the merge.
- CI merge issues:
   - The malloc shim libraries are renamed.
   - CMake gets very unhappy if you don't enable the C language and
     tries to link with the C compiler instead of the C++ compiler if
     you do enable it.
   - The Ubuntu packages for QEMU install a `binfmt_misc` activator for
     PowerPC64 little-endian, but set the page size to 4 KiB.  We then
     tried to run the tests (which expect 64 KiB pages) and became very
     confused when `mmap` returned 4 KiB-aligned memory.
 - Test failures:
   - Fix all of the issues UBsan found.
     - Underflow in `pointer_offset` when used to add negative offsets.
     - `CoreAlloc`'s `LocalState` accessed on a null `CoreAlloc` pointer.
     - Out of bounds access in the sizeclass list on attempts to access
       more memory than fits in the VA space.
     -
   - There was an integer overflow in `AddressSpace` that could cause it
     to try to allocate a zero-sized object, get a null pointer, and
     then try to do something with 0 - {size of the real allocation}.
   - The malloc tests weren't setting `errno` to 0 before doing
     calling `malloc`, which should set `errno` on failure, and then
     checking that `errno` was 0.
   - Don't call `PAL::error` on PAL allocation failure, return `nullptr`.
     The PALs were inconsistent about that and the new code expects to be
     able to report address-space exhaustion.
   - The malloc checks can behave differently with 0-sized allocations
     on different platforms but were very fragile about their
     expectations.
   - The malloc test didn't report failure for all of the ways that it
     could fail and so was spuriously passing on some platforms.
   - The perf test for external pointer is currently very slow on
     Windows.  The number of loops have been reduced and a timeout added
     for the Windows CI runs.
   - The logic to capture `errno` across calls was using
     `decltype(errno)`, which on some platforms where `errno` is a macro
     evaluated to `int&` and so they captured a reference rather than
     the value and failed to reset `errno`.
   - The Apple PAL can set `errno` on `notify_using` if it's called with
     memory that was not previously passed to `notify_not_using` but was
     not adequately protected against this and so would sometimes cause
     `malloc` to set `errno` to `EINVAL`.
2021-08-06 14:00:56 +01:00

109 lines
2.6 KiB
C++

#include <snmalloc.h>
#include <test/measuretime.h>
#include <test/setup.h>
#include <test/xoroshiro.h>
#include <unordered_set>
using namespace snmalloc;
namespace test
{
static constexpr size_t count_log = 20;
static constexpr size_t count = 1 << count_log;
// Pre allocate all the objects
size_t* objects[count];
NOINLINE void setup(xoroshiro::p128r64& r, Alloc& alloc)
{
for (size_t i = 0; i < count; i++)
{
size_t rand = (size_t)r.next();
size_t offset = bits::clz(rand);
if constexpr (bits::is64())
{
if (offset > 30)
offset = 30;
}
else if (offset > 20)
offset = 20;
size_t size = (rand & 15) << offset;
if (size < 16)
size = 16;
// store object
objects[i] = (size_t*)alloc.alloc(size);
if (objects[i] == nullptr)
abort();
// Store allocators size for this object
*objects[i] = alloc.alloc_size(objects[i]);
}
}
NOINLINE void teardown(Alloc& alloc)
{
// Deallocate everything
for (size_t i = 0; i < count; i++)
{
alloc.dealloc(objects[i]);
}
snmalloc::debug_check_empty<Globals>();
}
void test_external_pointer(xoroshiro::p128r64& r)
{
auto& alloc = ThreadAlloc::get();
// This is very slow on Windows at the moment. Until this is fixed, help
// CI terminate.
#if defined(NDEBUG) && !defined(_MSC_VER)
static constexpr size_t iterations = 10000000;
#else
# ifdef _MSC_VER
// Windows Debug build is very slow on this test.
// Reduce complexity to balance CI times.
static constexpr size_t iterations = 50000;
# else
static constexpr size_t iterations = 100000;
# endif
#endif
setup(r, alloc);
{
MeasureTime m;
m << "External pointer queries ";
for (size_t i = 0; i < iterations; i++)
{
size_t rand = (size_t)r.next();
size_t oid = rand & (((size_t)1 << count_log) - 1);
size_t* external_ptr = objects[oid];
size_t size = *external_ptr;
size_t offset = (size >> 4) * (rand & 15);
void* interior_ptr = pointer_offset(external_ptr, offset);
void* calced_external = alloc.external_pointer(interior_ptr);
if (calced_external != external_ptr)
abort();
}
}
teardown(alloc);
}
}
int main(int, char**)
{
#ifndef SNMALLOC_PASS_THROUGH // Depends on snmalloc specific features
setup();
xoroshiro::p128r64 r;
# ifdef NDEBUG
size_t nn = 30;
# else
size_t nn = 3;
# endif
for (size_t n = 0; n < nn; n++)
test::test_external_pointer(r);
return 0;
#endif
}