mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-04 22:49:32 +03:00
enable large OS page support on Windows
This commit is contained in:
parent
6eaf387891
commit
d6901558cd
6 changed files with 96 additions and 18 deletions
|
@ -36,6 +36,7 @@ bool _mi_os_shrink(void* p, size_t oldsize, size_t newsize);
|
||||||
void _mi_os_free(void* p, size_t size, mi_stats_t* stats);
|
void _mi_os_free(void* p, size_t size, mi_stats_t* stats);
|
||||||
bool _mi_os_protect(void* addr, size_t size);
|
bool _mi_os_protect(void* addr, size_t size);
|
||||||
bool _mi_os_unprotect(void* addr, size_t size);
|
bool _mi_os_unprotect(void* addr, size_t size);
|
||||||
|
void _mi_os_init(void); // called from process init
|
||||||
|
|
||||||
void* _mi_os_alloc_aligned(size_t size, size_t alignment, mi_os_tld_t* tld);
|
void* _mi_os_alloc_aligned(size_t size, size_t alignment, mi_os_tld_t* tld);
|
||||||
size_t _mi_os_page_size(void);
|
size_t _mi_os_page_size(void);
|
||||||
|
|
|
@ -216,6 +216,7 @@ typedef enum mi_option_e {
|
||||||
mi_option_page_reset,
|
mi_option_page_reset,
|
||||||
mi_option_cache_reset,
|
mi_option_cache_reset,
|
||||||
mi_option_pool_commit,
|
mi_option_pool_commit,
|
||||||
|
mi_option_large_os_pages,
|
||||||
mi_option_secure,
|
mi_option_secure,
|
||||||
mi_option_show_stats,
|
mi_option_show_stats,
|
||||||
mi_option_show_errors,
|
mi_option_show_errors,
|
||||||
|
|
|
@ -368,6 +368,7 @@ void mi_process_init(void) mi_attr_noexcept {
|
||||||
atexit(&mi_process_done);
|
atexit(&mi_process_done);
|
||||||
mi_process_setup_auto_thread_done();
|
mi_process_setup_auto_thread_done();
|
||||||
mi_stats_reset();
|
mi_stats_reset();
|
||||||
|
_mi_os_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mi_process_done(void) {
|
static void mi_process_done(void) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ static mi_option_desc_t options[_mi_option_last] = {
|
||||||
{ 0, UNINIT, "page_reset" },
|
{ 0, UNINIT, "page_reset" },
|
||||||
{ 0, UNINIT, "cache_reset" },
|
{ 0, UNINIT, "cache_reset" },
|
||||||
{ 0, UNINIT, "pool_commit" },
|
{ 0, UNINIT, "pool_commit" },
|
||||||
|
{ 0, UNINIT, "large_os_pages" }, // use large OS pages
|
||||||
#if MI_SECURE
|
#if MI_SECURE
|
||||||
{ MI_SECURE, INITIALIZED, "secure" }, // in secure build the environment setting is ignored
|
{ MI_SECURE, INITIALIZED, "secure" }, // in secure build the environment setting is ignored
|
||||||
#else
|
#else
|
||||||
|
|
108
src/os.c
108
src/os.c
|
@ -16,21 +16,86 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
/* -----------------------------------------------------------
|
/* -----------------------------------------------------------
|
||||||
Raw allocation on Windows (VirtualAlloc) and Unix's (mmap).
|
Initialization.
|
||||||
Defines a portable `mmap`, `munmap` and `mmap_trim`.
|
On windows initializes support for aligned allocation and
|
||||||
|
large OS pages (if MIMALLOC_LARGE_OS_PAGES is true).
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#if defined(MEM_EXTENDED_PARAMETER_TYPE_BITS) // rough check it VirtualAlloc2 is available (needs windows 10 or Windows server 2016)
|
|
||||||
#pragma comment(lib, "mincore.lib") // seems needed to resolve VirtualAlloc2
|
|
||||||
#define USE_VIRTUALALLOC2 // allows aligned allocation
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#include <sys/mman.h> // mmap
|
#include <sys/mman.h> // mmap
|
||||||
#include <unistd.h> // sysconf
|
#include <unistd.h> // sysconf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// if non-zero, use large page allocation
|
||||||
|
static size_t large_os_page_size = 0;
|
||||||
|
|
||||||
|
static bool use_large_os_page(size_t size, size_t alignment) {
|
||||||
|
// if we have access, check the size and alignment requirements
|
||||||
|
if (large_os_page_size == 0) return false;
|
||||||
|
return ((size % large_os_page_size) == 0 && (alignment % large_os_page_size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// We use VirtualAlloc2 for aligned allocation, but it is only supported on Windows 10 and Windows Server 2016.
|
||||||
|
// So, we need to look it up dynamically to run on older systems.
|
||||||
|
typedef PVOID (*VirtualAlloc2Ptr)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG );
|
||||||
|
static VirtualAlloc2Ptr pVirtualAlloc2 = NULL;
|
||||||
|
|
||||||
|
void _mi_os_init(void) {
|
||||||
|
// Try to get the VirtualAlloc2 function (only supported on Windows 10 and Windows Server 2016)
|
||||||
|
HINSTANCE hDll;
|
||||||
|
hDll = LoadLibrary("kernelbase.dll");
|
||||||
|
if (hDll!=NULL) {
|
||||||
|
pVirtualAlloc2 = (VirtualAlloc2Ptr)GetProcAddress(hDll, "VirtualAlloc2");
|
||||||
|
FreeLibrary(hDll);
|
||||||
|
}
|
||||||
|
// Try to see if large OS pages are supported
|
||||||
|
unsigned long err = 0;
|
||||||
|
bool ok = mi_option_is_enabled(mi_option_large_os_pages);
|
||||||
|
if (ok) {
|
||||||
|
// To use large pages on Windows, we first need access permission
|
||||||
|
// Set "Lock pages in memory" permission in the group policy editor
|
||||||
|
// <https://devblogs.microsoft.com/oldnewthing/20110128-00/?p=11643>
|
||||||
|
HANDLE token = NULL;
|
||||||
|
ok = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token);
|
||||||
|
if (ok) {
|
||||||
|
TOKEN_PRIVILEGES tp;
|
||||||
|
ok = LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &tp.Privileges[0].Luid);
|
||||||
|
if (ok) {
|
||||||
|
tp.PrivilegeCount = 1;
|
||||||
|
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
|
ok = AdjustTokenPrivileges(token, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
|
||||||
|
if (ok) {
|
||||||
|
err = GetLastError();
|
||||||
|
ok = (err == ERROR_SUCCESS);
|
||||||
|
if (ok) {
|
||||||
|
large_os_page_size = GetLargePageMinimum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle(token);
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
if (err==0) err = GetLastError();
|
||||||
|
_mi_warning_message("cannot enable large OS page support, error %lu\n", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void _mi_os_init() {
|
||||||
|
// nothing to do
|
||||||
|
use_large_os_page(0, 0); // dummy call to suppress warnings
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------
|
||||||
|
Raw allocation on Windows (VirtualAlloc) and Unix's (mmap).
|
||||||
|
Defines a portable `mmap`, `munmap` and `mmap_trim`.
|
||||||
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) {
|
uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) {
|
||||||
uintptr_t x = (sz / alignment) * alignment;
|
uintptr_t x = (sz / alignment) * alignment;
|
||||||
|
@ -92,9 +157,14 @@ static bool mi_munmap(void* addr, size_t size)
|
||||||
static void* mi_mmap(void* addr, size_t size, int extra_flags, mi_stats_t* stats) {
|
static void* mi_mmap(void* addr, size_t size, int extra_flags, mi_stats_t* stats) {
|
||||||
UNUSED(stats);
|
UNUSED(stats);
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
void* p;
|
void* p = NULL;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
p = VirtualAlloc(addr, size, MEM_RESERVE | MEM_COMMIT | extra_flags, PAGE_READWRITE);
|
if (use_large_os_page(size, 0)) {
|
||||||
|
p = VirtualAlloc(addr, size, MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT | extra_flags, PAGE_READWRITE);
|
||||||
|
}
|
||||||
|
if (p == NULL) {
|
||||||
|
p = VirtualAlloc(addr, size, MEM_RESERVE | MEM_COMMIT | extra_flags, PAGE_READWRITE);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#if !defined(MAP_ANONYMOUS)
|
#if !defined(MAP_ANONYMOUS)
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
|
@ -124,14 +194,18 @@ static void* mi_mmap(void* addr, size_t size, int extra_flags, mi_stats_t* stats
|
||||||
static void* mi_mmap_aligned(size_t size, size_t alignment, mi_stats_t* stats) {
|
static void* mi_mmap_aligned(size_t size, size_t alignment, mi_stats_t* stats) {
|
||||||
if (alignment < _mi_os_page_size() || ((alignment & (~alignment + 1)) != alignment)) return NULL;
|
if (alignment < _mi_os_page_size() || ((alignment & (~alignment + 1)) != alignment)) return NULL;
|
||||||
void* p = NULL;
|
void* p = NULL;
|
||||||
#if defined(_WIN32) && defined(USE_VIRTUALALLOC2)
|
#if defined(_WIN32) && defined(MEM_EXTENDED_PARAMETER_TYPE_BITS)
|
||||||
// on modern Windows use VirtualAlloc2
|
if (pVirtualAlloc2 != NULL) {
|
||||||
MEM_ADDRESS_REQUIREMENTS reqs = {0};
|
// on modern Windows try use VirtualAlloc2
|
||||||
reqs.Alignment = alignment;
|
MEM_ADDRESS_REQUIREMENTS reqs = {0};
|
||||||
MEM_EXTENDED_PARAMETER param = { 0 };
|
reqs.Alignment = alignment;
|
||||||
param.Type = MemExtendedParameterAddressRequirements;
|
MEM_EXTENDED_PARAMETER param = { 0 };
|
||||||
param.Pointer = &reqs;
|
param.Type = MemExtendedParameterAddressRequirements;
|
||||||
p = VirtualAlloc2(NULL, NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, ¶m, 1);
|
param.Pointer = &reqs;
|
||||||
|
DWORD extra_flags = 0;
|
||||||
|
if (use_large_os_page(size, alignment)) extra_flags |= MEM_LARGE_PAGES;
|
||||||
|
p = (*pVirtualAlloc2)(NULL, NULL, size, MEM_RESERVE | MEM_COMMIT | extra_flags, PAGE_READWRITE, ¶m, 1);
|
||||||
|
}
|
||||||
#elif defined(MAP_ALIGNED)
|
#elif defined(MAP_ALIGNED)
|
||||||
// on BSD, use the aligned mmap api
|
// on BSD, use the aligned mmap api
|
||||||
size_t n = _mi_bsr(alignment);
|
size_t n = _mi_bsr(alignment);
|
||||||
|
|
|
@ -608,7 +608,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p
|
||||||
else {
|
else {
|
||||||
mi_assert(pq->first == page);
|
mi_assert(pq->first == page);
|
||||||
}
|
}
|
||||||
mi_assert_internal(mi_page_immediate_available(page));
|
mi_assert_internal(page == NULL || mi_page_immediate_available(page));
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue