Merge pull request #185 from nwf/pal-page-size

Move OS_PAGE_SIZE to PAL, add Linux PowerPC w/ 64KiB pages
This commit is contained in:
Matthew Parkinson
2020-05-26 09:43:15 +01:00
committed by GitHub
18 changed files with 112 additions and 41 deletions

View File

@@ -19,6 +19,10 @@
# define PLATFORM_IS_ARM
#endif
#if defined(__powerpc__) || defined(__powerpc64__)
# define PLATFORM_IS_POWERPC
#endif
namespace snmalloc
{
/**
@@ -44,6 +48,14 @@ namespace snmalloc
StrictProvenance = (1 << 2),
};
enum AalName : int
{
ARM,
PowerPC,
X86,
X86_SGX,
};
/**
* Architecture Abstraction Layer. Includes default implementations of some
* functions using compiler builtins. Falls back to the definitions in the
@@ -133,6 +145,8 @@ namespace snmalloc
# include "aal_x86_sgx.h"
#elif defined(PLATFORM_IS_ARM)
# include "aal_arm.h"
#elif defined(PLATFORM_IS_POWERPC)
# include "aal_powerpc.h"
#endif
namespace snmalloc

View File

@@ -27,6 +27,10 @@ namespace snmalloc
static constexpr uint64_t aal_features =
IntegerPointers | NoCpuCycleCounters;
static constexpr enum AalName aal_name = ARM;
static constexpr size_t smallest_page_size = 0x1000;
/**
* On pipelined processors, notify the core that we are in a spin loop and
* that speculative execution past this point may not be a performance gain.

37
src/aal/aal_powerpc.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#if defined(__powerpc64__)
# define SNMALLOC_VA_BITS_64
#else
# define SNMALLOC_VA_BITS_32
#endif
namespace snmalloc
{
/**
* ARM-specific architecture abstraction layer.
*/
class AAL_PowerPC
{
public:
/**
* Bitmap of AalFeature flags
*/
static constexpr uint64_t aal_features = IntegerPointers;
static constexpr enum AalName aal_name = PowerPC;
static constexpr size_t smallest_page_size = 0x1000;
/**
* On pipelined processors, notify the core that we are in a spin loop and
* that speculative execution past this point may not be a performance gain.
*/
static inline void pause()
{
__asm__ volatile("or 27,27,27"); // "yield"
}
};
using AAL_Arch = AAL_PowerPC;
} // namespace snmalloc

View File

@@ -60,6 +60,10 @@ namespace snmalloc
*/
static constexpr uint64_t aal_features = IntegerPointers;
static constexpr enum AalName aal_name = X86;
static constexpr size_t smallest_page_size = 0x1000;
/**
* On pipelined processors, notify the core that we are in a spin loop and
* that speculative execution past this point may not be a performance gain.

View File

@@ -26,6 +26,10 @@ namespace snmalloc
*/
static constexpr uint64_t aal_features = IntegerPointers;
static constexpr enum AalName aal_name = X86_SGX;
static constexpr size_t smallest_page_size = 0x1000;
/**
* On pipelined processors, notify the core that we are in a spin loop and
* that speculative execution past this point may not be a performance gain.

View File

@@ -733,12 +733,6 @@ namespace snmalloc
size_t size1 = sizeclass_to_size(sc1);
size_t size2 = sizeclass_to_size(sc2);
// All medium size classes are page aligned.
if (i > NUM_SMALL_CLASSES)
{
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(nullptr, size1));
}
SNMALLOC_ASSERT(sc1 == i);
SNMALLOC_ASSERT(sc1 == sc2);
SNMALLOC_ASSERT(size1 == size);

View File

@@ -92,18 +92,7 @@ namespace snmalloc
// Used to isolate values on cache lines to prevent false sharing.
static constexpr size_t CACHELINE_SIZE = 64;
// Used to keep Superslab metadata committed.
static constexpr size_t OS_PAGE_SIZE = 0x1000;
static constexpr size_t PAGE_ALIGNED_SIZE = OS_PAGE_SIZE << INTERMEDIATE_BITS;
// Some system headers (e.g. Linux' sys/user.h, FreeBSD's machine/param.h)
// define `PAGE_SIZE` as a macro. We don't use `PAGE_SIZE` as our variable
// name, to avoid conflicts, but if we do see a macro definition then check
// that our value matches the platform's expected value.
#ifdef PAGE_SIZE
static_assert(
PAGE_SIZE == OS_PAGE_SIZE,
"Page size from system header does not match snmalloc config page size.");
#endif
// Minimum allocation size is space for two pointers.
static_assert(bits::next_pow2_const(sizeof(void*)) == sizeof(void*));

View File

@@ -85,11 +85,10 @@ namespace snmalloc
void* p = pointer_offset(this, (static_cast<size_t>(index) << 8));
free--;
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, OS_PAGE_SIZE));
size = bits::align_up(size, OS_PAGE_SIZE);
if constexpr (zero_mem == YesZero)
memory_provider.template zero<true>(p, size);
memory_provider.zero(p, size);
else
UNUSED(size);
return p;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../pal/pal_consts.h"
#include "../pal/pal.h"
#include "allocconfig.h"
namespace snmalloc

View File

@@ -59,4 +59,25 @@ namespace snmalloc
*/
template<PalFeatures F, typename PAL = Pal>
constexpr static bool pal_supports = (PAL::pal_features & F) == F;
// Used to keep Superslab metadata committed.
static constexpr size_t OS_PAGE_SIZE = Pal::page_size;
static_assert(
bits::next_pow2_const(OS_PAGE_SIZE) == OS_PAGE_SIZE,
"OS_PAGE_SIZE must be a power of two");
static_assert(
OS_PAGE_SIZE % Aal::smallest_page_size == 0,
"The smallest architectural page size must divide OS_PAGE_SIZE");
// Some system headers (e.g. Linux' sys/user.h, FreeBSD's machine/param.h)
// define `PAGE_SIZE` as a macro. We don't use `PAGE_SIZE` as our variable
// name, to avoid conflicts, but if we do see a macro definition then check
// that our value matches the platform's expected value.
#ifdef PAGE_SIZE
static_assert(
PAGE_SIZE == OS_PAGE_SIZE,
"Page size from system header does not match snmalloc config page size.");
#endif
} // namespace snmalloc

View File

@@ -32,9 +32,9 @@ namespace snmalloc
template<bool page_aligned = false>
void zero(void* p, size_t size)
{
if (page_aligned || is_aligned_block<OS_PAGE_SIZE>(p, size))
if (page_aligned || is_aligned_block<page_size>(p, size))
{
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, size));
SNMALLOC_ASSERT(is_aligned_block<page_size>(p, size));
void* r = mmap(
p,
size,

View File

@@ -33,7 +33,7 @@ namespace snmalloc
*/
void notify_not_using(void* p, size_t size) noexcept
{
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, size));
SNMALLOC_ASSERT(is_aligned_block<OS::page_size>(p, size));
madvise(p, size, MADV_FREE);
}
};

View File

@@ -1,7 +1,6 @@
#pragma once
#include "../ds/bits.h"
#include "../mem/allocconfig.h"
#if defined(FreeBSD_KERNEL)
extern "C"

View File

@@ -2,7 +2,6 @@
#if defined(__linux__)
# include "../ds/bits.h"
# include "../mem/allocconfig.h"
# include "pal_posix.h"
# include <string.h>
@@ -26,6 +25,9 @@ namespace snmalloc
*/
static constexpr uint64_t pal_features = PALPOSIX::pal_features;
static constexpr size_t page_size =
Aal::aal_name == PowerPC ? 0x10000 : 0x1000;
/**
* OS specific function for zeroing memory.
*
@@ -41,12 +43,12 @@ namespace snmalloc
// MADV_DONTNEED. switch back to memset only for QEMU.
# ifndef SNMALLOC_QEMU_WORKAROUND
if (
(page_aligned || is_aligned_block<OS_PAGE_SIZE>(p, size)) &&
(size > SLAB_SIZE))
(page_aligned || is_aligned_block<page_size>(p, size)) &&
(size > 16 * page_size))
{
// Only use this on large allocations as memset faster, and doesn't
// introduce IPI so faster for small allocations.
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, size));
SNMALLOC_ASSERT(is_aligned_block<page_size>(p, size));
madvise(p, size, MADV_DONTNEED);
}
else

View File

@@ -19,6 +19,9 @@ namespace snmalloc
* PAL supports.
*/
static constexpr uint64_t pal_features = 0;
static constexpr size_t page_size = 0x1000;
[[noreturn]] static void error(const char* const str)
{
UNUSED(str);

View File

@@ -1,7 +1,6 @@
#pragma once
#include "../ds/bits.h"
#include "../mem/allocconfig.h"
namespace snmalloc
{

View File

@@ -1,7 +1,6 @@
#pragma once
#include "../ds/address.h"
#include "../mem/allocconfig.h"
#if defined(BACKTRACE_HEADER)
# include BACKTRACE_HEADER
#endif
@@ -39,6 +38,8 @@ namespace snmalloc
*/
static constexpr uint64_t pal_features = LazyCommit;
static constexpr size_t page_size = 0x1000;
static void print_stack_trace()
{
#ifdef BACKTRACE_HEADER
@@ -72,7 +73,7 @@ namespace snmalloc
*/
void notify_not_using(void* p, size_t size) noexcept
{
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, size));
SNMALLOC_ASSERT(is_aligned_block<OS::page_size>(p, size));
#ifdef USE_POSIX_COMMIT_CHECKS
mprotect(p, size, PROT_NONE);
#else
@@ -92,7 +93,7 @@ namespace snmalloc
void notify_using(void* p, size_t size) noexcept
{
SNMALLOC_ASSERT(
is_aligned_block<OS_PAGE_SIZE>(p, size) || (zero_mem == NoZero));
is_aligned_block<OS::page_size>(p, size) || (zero_mem == NoZero));
#ifdef USE_POSIX_COMMIT_CHECKS
mprotect(p, size, PROT_READ | PROT_WRITE);
@@ -119,9 +120,9 @@ namespace snmalloc
template<bool page_aligned = false>
void zero(void* p, size_t size) noexcept
{
if (page_aligned || is_aligned_block<OS_PAGE_SIZE>(p, size))
if (page_aligned || is_aligned_block<OS::page_size>(p, size))
{
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, size));
SNMALLOC_ASSERT(is_aligned_block<OS::page_size>(p, size));
void* r = mmap(
p,
size,

View File

@@ -2,7 +2,6 @@
#include "../ds/address.h"
#include "../ds/bits.h"
#include "../mem/allocconfig.h"
#ifdef _WIN32
# ifndef _MSC_VER
@@ -83,6 +82,8 @@ namespace snmalloc
# endif
;
static constexpr size_t page_size = 0x1000;
/**
* Check whether the low memory state is still in effect. This is an
* expensive operation and should not be on any fast paths.
@@ -115,7 +116,7 @@ namespace snmalloc
/// Notify platform that we will not be using these pages
void notify_not_using(void* p, size_t size) noexcept
{
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, size));
SNMALLOC_ASSERT(is_aligned_block<page_size>(p, size));
BOOL ok = VirtualFree(p, size, MEM_DECOMMIT);
@@ -128,7 +129,7 @@ namespace snmalloc
void notify_using(void* p, size_t size) noexcept
{
SNMALLOC_ASSERT(
is_aligned_block<OS_PAGE_SIZE>(p, size) || (zero_mem == NoZero));
is_aligned_block<page_size>(p, size) || (zero_mem == NoZero));
void* r = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
@@ -140,9 +141,9 @@ namespace snmalloc
template<bool page_aligned = false>
void zero(void* p, size_t size) noexcept
{
if (page_aligned || is_aligned_block<OS_PAGE_SIZE>(p, size))
if (page_aligned || is_aligned_block<page_size>(p, size))
{
SNMALLOC_ASSERT(is_aligned_block<OS_PAGE_SIZE>(p, size));
SNMALLOC_ASSERT(is_aligned_block<page_size>(p, size));
notify_not_using(p, size);
notify_using<YesZero>(p, size);
}