Skip to content

Commit

Permalink
src: add large page support for macOS
Browse files Browse the repository at this point in the history
Proposal to bring the support for this platform.
We assume the pse36 cpu flag is present for 2MB
large page support present in recent years
in mac line (not to be backported to 10.x anyway).
Recommended better for mac production servers rather
than casual mac books.

PR-URL: #28977
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
devnexen authored and BridgeAR committed Sep 3, 2019
1 parent 10bae2e commit 4d4583e
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 25 deletions.
8 changes: 5 additions & 3 deletions configure.py
Expand Up @@ -1035,16 +1035,18 @@ def configure_node(o):
else: else:
o['variables']['node_use_dtrace'] = 'false' o['variables']['node_use_dtrace'] = 'false'


if options.node_use_large_pages and not flavor in ('linux', 'freebsd'): if options.node_use_large_pages and not flavor in ('linux', 'freebsd', 'mac'):
raise Exception( raise Exception(
'Large pages are supported only on Linux Systems.') 'Large pages are supported only on Linux, FreeBSD and MacOS Systems.')
if options.node_use_large_pages and flavor in ('linux', 'freebsd'): if options.node_use_large_pages and flavor in ('linux', 'freebsd', 'mac'):
if options.shared or options.enable_static: if options.shared or options.enable_static:
raise Exception( raise Exception(
'Large pages are supported only while creating node executable.') 'Large pages are supported only while creating node executable.')
if target_arch!="x64": if target_arch!="x64":
raise Exception( raise Exception(
'Large pages are supported only x64 platform.') 'Large pages are supported only x64 platform.')
if flavor == 'mac':
info('macOS server with 32GB or more is recommended')
if flavor == 'linux': if flavor == 'linux':
# Example full version string: 2.6.32-696.28.1.el6.x86_64 # Example full version string: 2.6.32-696.28.1.el6.x86_64
FULL_KERNEL_VERSION=os.uname()[2] FULL_KERNEL_VERSION=os.uname()[2]
Expand Down
2 changes: 1 addition & 1 deletion node.gyp
Expand Up @@ -817,7 +817,7 @@
}], }],
], ],
}], }],
[ 'node_use_large_pages=="true" and OS in "linux freebsd"', { [ 'node_use_large_pages=="true" and OS in "linux freebsd mac"', {
'defines': [ 'NODE_ENABLE_LARGE_CODE_PAGES=1' ], 'defines': [ 'NODE_ENABLE_LARGE_CODE_PAGES=1' ],
# The current implementation of Large Pages is under Linux. # The current implementation of Large Pages is under Linux.
# Other implementations are possible but not currently supported. # Other implementations are possible but not currently supported.
Expand Down
98 changes: 77 additions & 21 deletions src/large_pages/node_large_page.cc
Expand Up @@ -30,6 +30,8 @@
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/user.h> #include <sys/user.h>
#elif defined(__APPLE__)
#include <mach/vm_map.h>
#endif #endif
#include <unistd.h> // readlink #include <unistd.h> // readlink


Expand Down Expand Up @@ -212,6 +214,42 @@ static struct text_region FindNodeTextRegion() {
} }
start += cursz; start += cursz;
} }
#elif defined(__APPLE__)
struct text_region nregion;
nregion.found_text_region = false;
struct vm_region_submap_info_64 map;
mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
vm_address_t addr = 0UL;
vm_size_t size = 0;
natural_t depth = 1;

while (true) {
if (vm_region_recurse_64(mach_task_self(), &addr, &size, &depth,
reinterpret_cast<vm_region_info_64_t>(&map),
&count) != KERN_SUCCESS) {
break;
}

if (map.is_submap) {
depth++;
} else {
char* start = reinterpret_cast<char*>(hugepage_align_up(addr));
char* end = reinterpret_cast<char*>(hugepage_align_down(addr+size));
size_t esize = end - start;

if (end > start && (map.protection & VM_PROT_READ) != 0 &&
(map.protection & VM_PROT_EXECUTE) != 0) {
nregion.found_text_region = true;
nregion.from = start;
nregion.to = end;
nregion.total_hugepages = esize / hps;
break;
}

addr += size;
size = 0;
}
}
#endif #endif
return nregion; return nregion;
} }
Expand Down Expand Up @@ -267,11 +305,15 @@ static bool IsSuperPagesEnabled() {
// 2: This function should not call any function(s) that might be moved. // 2: This function should not call any function(s) that might be moved.
// a. map a new area and copy the original code there // a. map a new area and copy the original code there
// b. mmap using the start address with MAP_FIXED so we get exactly // b. mmap using the start address with MAP_FIXED so we get exactly
// the same virtual address // the same virtual address (except on macOS).
// c. madvise with MADV_HUGE_PAGE // c. madvise with MADV_HUGE_PAGE
// d. If successful copy the code there and unmap the original region // d. If successful copy the code there and unmap the original region
int int
#if !defined(__APPLE__)
__attribute__((__section__(".lpstub"))) __attribute__((__section__(".lpstub")))
#else
__attribute__((__section__("__TEXT,__lpstub")))
#endif
__attribute__((__aligned__(hps))) __attribute__((__aligned__(hps)))
__attribute__((__noinline__)) __attribute__((__noinline__))
MoveTextRegionToLargePages(const text_region& r) { MoveTextRegionToLargePages(const text_region& r) {
Expand All @@ -289,6 +331,9 @@ MoveTextRegionToLargePages(const text_region& r) {
PrintSystemError(errno); PrintSystemError(errno);
return -1; return -1;
} }
OnScopeLeave munmap_on_return([nmem, size]() {
if (-1 == munmap(nmem, size)) PrintSystemError(errno);
});


memcpy(nmem, r.from, size); memcpy(nmem, r.from, size);


Expand All @@ -302,7 +347,6 @@ MoveTextRegionToLargePages(const text_region& r) {
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1 , 0); MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1 , 0);
if (tmem == MAP_FAILED) { if (tmem == MAP_FAILED) {
PrintSystemError(errno); PrintSystemError(errno);
munmap(nmem, size);
return -1; return -1;
} }


Expand All @@ -313,11 +357,6 @@ MoveTextRegionToLargePages(const text_region& r) {
if (ret == -1) { if (ret == -1) {
PrintSystemError(errno); PrintSystemError(errno);
} }
ret = munmap(nmem, size);
if (ret == -1) {
PrintSystemError(errno);
}

return -1; return -1;
} }
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
Expand All @@ -327,32 +366,46 @@ MoveTextRegionToLargePages(const text_region& r) {
MAP_ALIGNED_SUPER, -1 , 0); MAP_ALIGNED_SUPER, -1 , 0);
if (tmem == MAP_FAILED) { if (tmem == MAP_FAILED) {
PrintSystemError(errno); PrintSystemError(errno);
munmap(nmem, size);
return -1; return -1;
} }
#endif #elif defined(__APPLE__)

// There is not enough room to reserve the mapping close
memcpy(start, nmem, size); // to the region address so we content to give a hint
ret = mprotect(start, size, PROT_READ | PROT_EXEC); // without forcing the new address being closed to.
// We explicitally gives all permission since we plan
// to write into it.
tmem = mmap(start, size,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS,
VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
if (tmem == MAP_FAILED) {
PrintSystemError(errno);
return -1;
}
memcpy(tmem, nmem, size);
ret = mprotect(start, size, PROT_READ | PROT_WRITE | PROT_EXEC);
if (ret == -1) { if (ret == -1) {
PrintSystemError(errno); PrintSystemError(errno);
ret = munmap(tmem, size); ret = munmap(tmem, size);
if (ret == -1) { if (ret == -1) {
PrintSystemError(errno); PrintSystemError(errno);
} }
ret = munmap(nmem, size);
if (ret == -1) {
PrintSystemError(errno);
}
return -1; return -1;
} }
memcpy(start, tmem, size);
#else
memcpy(start, nmem, size);
#endif


// Release the old/temporary mapped region ret = mprotect(start, size, PROT_READ | PROT_EXEC);
ret = munmap(nmem, size);
if (ret == -1) { if (ret == -1) {
PrintSystemError(errno); PrintSystemError(errno);
ret = munmap(tmem, size);
if (ret == -1) {
PrintSystemError(errno);
}
return -1;
} }

return ret; return ret;
} }


Expand All @@ -369,16 +422,19 @@ int MapStaticCodeToLargePages() {
return MoveTextRegionToLargePages(r); return MoveTextRegionToLargePages(r);


return -1; return -1;
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__) || defined(__APPLE__)
return MoveTextRegionToLargePages(r); return MoveTextRegionToLargePages(r);
#endif #endif
} }


bool IsLargePagesEnabled() { bool IsLargePagesEnabled() {
#if defined(__linux__) #if defined(__linux__)
return IsTransparentHugePagesEnabled(); return IsTransparentHugePagesEnabled();
#else #elif defined(__FreeBSD__)
return IsSuperPagesEnabled(); return IsSuperPagesEnabled();
#elif defined(__APPLE__)
// pse-36 flag is present in recent mac x64 products.
return true;
#endif #endif
} }


Expand Down

0 comments on commit 4d4583e

Please sign in to comment.