Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip aligned allocation on SV39 MMUs #949

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,16 @@ if(MINGW)
add_definitions(-D_WIN32_WINNT=0x600)
endif()

# Check /proc/cpuinfo for an SV39 MMU and define a constant if one is
# found. We will want to skip the aligned hinting in that case.
if (EXISTS /proc/cpuinfo)
file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$")
if (mi_sv39_mmu)
MESSAGE( STATUS "SV39 MMU detected" )
list(APPEND mi_defines MI_SV39_MMU=1)
endif()
endif()

# extra needed libraries

# we prefer -l<lib> test over `find_library` as sometimes core libraries
Expand Down
33 changes: 27 additions & 6 deletions src/os.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats
-------------------------------------------------------------- */

// On 64-bit systems, we can do efficient aligned allocation by using
// the 2TiB to 30TiB area to allocate those.
#if (MI_INTPTR_SIZE >= 8)
// the 2TiB to 30TiB area to allocate those. The one exception is on
// 64-bit RISC-V systems that have an SV39 MMU; there the 256GiB+
// range (and specifically the 2TiB+ range) will not be usable.
#if (MI_INTPTR_SIZE >= 8) && (!defined(MI_SV39_MMU) || MI_SV39_MMU == 0)
static mi_decl_cache_align _Atomic(uintptr_t)aligned_base;

// Return a MI_SEGMENT_SIZE aligned address that is probably available.
Expand Down Expand Up @@ -213,6 +215,10 @@ static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bo
// Primitive aligned allocation from the OS.
// This function guarantees the allocated memory is aligned.
static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** base, mi_stats_t* stats) {
#if (MI_INTPTR_SIZE < 8) || (defined(MI_SV39_MMU) && MI_SV39_MMU != 0)
MI_UNUSED(allow_large); // not used on 32-bit/SV39 systems
#endif

mi_assert_internal(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0));
mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0);
mi_assert_internal(is_large != NULL);
Expand All @@ -222,18 +228,33 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit
if (!(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0))) return NULL;
size = _mi_align_up(size, _mi_os_page_size());

// try first with a hint (this will be aligned directly on Win 10+ or BSD)
void* p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero, stats);
void* p = NULL;

#if (MI_INTPTR_SIZE >= 8) && (!defined(MI_SV39_MMU) || MI_SV39_MMU == 0)
// Try first with a hint. This will be usually be aligned directly
// on Win 10+ or BSD, but if this is a 32-bit or SV39 system, we
// don't bother -- it's not going to work.
p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero, stats);
if (p == NULL) return NULL;
#endif

// aligned already?
if (((uintptr_t)p % alignment) == 0) {
if (p && ((uintptr_t)p % alignment) == 0) {
*base = p;
}
else {
// if not aligned, free it, overallocate, and unmap around it
// If p is not aligned, then either we tried and failed to obtain
// an aligned allocation, or we didn't try at all. Only one of
// these is a warning scenario.
#if (MI_INTPTR_SIZE >= 8) && (!defined(MI_SV39_MMU) || MI_SV39_MMU == 0)
// Skip the warning and the free() if we never attempted an aligned
// allocation in the first place.
_mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n", size, p, alignment, commit);
mi_os_prim_free(p, size, commit, stats);
#endif

// now overallocate

if (size >= (SIZE_MAX - alignment)) return NULL; // overflow
const size_t over_size = size + alignment;

Expand Down