summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure.py33
-rw-r--r--doc/api/cli.md17
-rw-r--r--doc/node.110
-rw-r--r--node.gyp5
-rw-r--r--node.gypi6
-rw-r--r--src/large_pages/node_large_page.cc19
-rw-r--r--src/node.cc30
-rw-r--r--src/node_options.cc9
-rw-r--r--src/node_options.h1
-rw-r--r--test/parallel/test-startup-large-pages.js29
10 files changed, 101 insertions, 58 deletions
diff --git a/configure.py b/configure.py
index 95766d405a..de27bb3403 100755
--- a/configure.py
+++ b/configure.py
@@ -404,17 +404,6 @@ parser.add_option('--with-etw',
dest='with_etw',
help='build with ETW (default is true on Windows)')
-parser.add_option('--use-largepages',
- action='store_true',
- dest='node_use_large_pages',
- help='build with Large Pages support. This feature is supported only on Linux kernel' +
- '>= 2.6.38 with Transparent Huge pages enabled and FreeBSD')
-
-parser.add_option('--use-largepages-script-lld',
- action='store_true',
- dest='node_use_large_pages_script_lld',
- help='link against the LLVM ld linker script. Implies -fuse-ld=lld in the linker flags')
-
intl_optgroup.add_option('--with-intl',
action='store',
dest='with_intl',
@@ -1068,28 +1057,6 @@ def configure_node(o):
else:
o['variables']['node_use_dtrace'] = 'false'
- if options.node_use_large_pages and not flavor in ('linux', 'freebsd', 'mac'):
- raise Exception(
- 'Large pages are supported only on Linux, FreeBSD and MacOS Systems.')
- if options.node_use_large_pages and flavor in ('linux', 'freebsd', 'mac'):
- if options.shared or options.enable_static:
- raise Exception(
- 'Large pages are supported only while creating node executable.')
- if target_arch!="x64":
- raise Exception(
- 'Large pages are supported only x64 platform.')
- if flavor == 'mac':
- info('macOS server with 32GB or more is recommended')
- if flavor == 'linux':
- # Example full version string: 2.6.32-696.28.1.el6.x86_64
- FULL_KERNEL_VERSION=os.uname()[2]
- KERNEL_VERSION=FULL_KERNEL_VERSION.split('-')[0]
- if KERNEL_VERSION < "2.6.38" and flavor == 'linux':
- raise Exception(
- 'Large pages need Linux kernel version >= 2.6.38')
- o['variables']['node_use_large_pages'] = b(options.node_use_large_pages)
- o['variables']['node_use_large_pages_script_lld'] = b(options.node_use_large_pages_script_lld)
-
if options.no_ifaddrs:
o['defines'] += ['SUNOS_NO_IFADDRS']
diff --git a/doc/api/cli.md b/doc/api/cli.md
index f3d5df070c..d098a199e0 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -876,6 +876,22 @@ environment variables.
See `SSL_CERT_DIR` and `SSL_CERT_FILE`.
+### `--use-largepages=mode`
+<!-- YAML
+added: REPLACEME
+-->
+
+Re-map the Node.js static code to large memory pages at startup. If supported on
+the target system, this will cause the Node.js static code to be moved onto 2
+MiB pages instead of 4 KiB pages.
+
+The following values are valid for `mode`:
+* `off`: No mapping will be attempted. This is the default.
+* `on`: If supported by the OS, mapping will be attempted. Failure to map will
+ be ignored and a message will be printed to standard error.
+* `silent`: If supported by the OS, mapping will be attempted. Failure to map
+ will be ignored and will not be reported.
+
### `--v8-options`
<!-- YAML
added: v0.1.3
@@ -1133,6 +1149,7 @@ Node.js options that are allowed are:
* `--track-heap-objects`
* `--unhandled-rejections`
* `--use-bundled-ca`
+* `--use-largepages`
* `--use-openssl-ca`
* `--v8-pool-size`
* `--zero-fill-buffers`
diff --git a/doc/node.1 b/doc/node.1
index c783195c95..4c63477889 100644
--- a/doc/node.1
+++ b/doc/node.1
@@ -402,6 +402,16 @@ See
and
.Ev SSL_CERT_FILE .
.
+.It Fl -use-largepages Ns = Ns Ar mode
+Re-map the Node.js static code to large memory pages at startup. If supported on
+the target system, this will cause the Node.js static code to be moved onto 2
+MiB pages instead of 4 KiB pages.
+.Pp
+.Ar mode
+must have one of the following values:
+`off` (the default value, meaning do not map), `on` (map and ignore failure,
+reporting it to stderr), or `silent` (map and silently ignore failure).
+.
.It Fl -v8-options
Print V8 command-line options.
.
diff --git a/node.gyp b/node.gyp
index 014aea7547..6569f1826b 100644
--- a/node.gyp
+++ b/node.gyp
@@ -836,10 +836,9 @@
}],
],
}],
- [ 'node_use_large_pages=="true" and OS in "linux freebsd mac"', {
+ [ 'OS in "linux freebsd mac" and '
+ 'target_arch=="x64"', {
'defines': [ 'NODE_ENABLE_LARGE_CODE_PAGES=1' ],
- # The current implementation of Large Pages is under Linux.
- # Other implementations are possible but not currently supported.
'sources': [
'src/large_pages/node_large_page.cc',
'src/large_pages/node_large_page.h'
diff --git a/node.gypi b/node.gypi
index b811829f4f..0751416c88 100644
--- a/node.gypi
+++ b/node.gypi
@@ -308,8 +308,7 @@
}],
[ 'OS=="linux" and '
'target_arch=="x64" and '
- 'node_use_large_pages=="true" and '
- 'node_use_large_pages_script_lld=="false"', {
+ 'llvm_version=="0.0"', {
'ldflags': [
'-Wl,-T',
'<!(realpath src/large_pages/ld.implicit.script)',
@@ -317,8 +316,7 @@
}],
[ 'OS=="linux" and '
'target_arch=="x64" and '
- 'node_use_large_pages=="true" and '
- 'node_use_large_pages_script_lld=="true"', {
+ 'llvm_version!="0.0"', {
'ldflags': [
'-Wl,-T',
'<!(realpath src/large_pages/ld.implicit.script.lld)',
diff --git a/src/large_pages/node_large_page.cc b/src/large_pages/node_large_page.cc
index 68fa178b40..3897b819e8 100644
--- a/src/large_pages/node_large_page.cc
+++ b/src/large_pages/node_large_page.cc
@@ -62,7 +62,7 @@
// Map a new area and copy the original code there
// Use mmap using the start address with MAP_FIXED so we get exactly the
// same virtual address
-// Use madvise with MADV_HUGE_PAGE to use Anonymous 2M Pages
+// Use madvise with MADV_HUGEPAGE to use Anonymous 2M Pages
// If successful copy the code there and unmap the original region.
extern char __nodetext;
@@ -308,7 +308,7 @@ static bool IsSuperPagesEnabled() {
// a. map a new area and copy the original code there
// b. mmap using the start address with MAP_FIXED so we get exactly
// the same virtual address (except on macOS).
-// c. madvise with MADV_HUGE_PAGE
+// c. madvise with MADV_HUGEPAGE
// d. If successful copy the code there and unmap the original region
int
#if !defined(__APPLE__)
@@ -333,9 +333,6 @@ MoveTextRegionToLargePages(const text_region& r) {
PrintSystemError(errno);
return -1;
}
- auto munmap_on_return = OnScopeLeave([nmem, size]() {
- if (-1 == munmap(nmem, size)) PrintSystemError(errno);
- });
memcpy(nmem, r.from, size);
@@ -352,13 +349,14 @@ MoveTextRegionToLargePages(const text_region& r) {
return -1;
}
- ret = madvise(tmem, size, MADV_HUGEPAGE);
+ ret = madvise(tmem, size, 14 /* MADV_HUGEPAGE */);
if (ret == -1) {
PrintSystemError(errno);
ret = munmap(tmem, size);
if (ret == -1) {
PrintSystemError(errno);
}
+ if (-1 == munmap(nmem, size)) PrintSystemError(errno);
return -1;
}
memcpy(start, nmem, size);
@@ -369,6 +367,7 @@ MoveTextRegionToLargePages(const text_region& r) {
MAP_ALIGNED_SUPER, -1 , 0);
if (tmem == MAP_FAILED) {
PrintSystemError(errno);
+ if (-1 == munmap(nmem, size)) PrintSystemError(errno);
return -1;
}
#elif defined(__APPLE__)
@@ -383,6 +382,7 @@ MoveTextRegionToLargePages(const text_region& r) {
VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
if (tmem == MAP_FAILED) {
PrintSystemError(errno);
+ if (-1 == munmap(nmem, size)) PrintSystemError(errno);
return -1;
}
memcpy(tmem, nmem, size);
@@ -393,6 +393,7 @@ MoveTextRegionToLargePages(const text_region& r) {
if (ret == -1) {
PrintSystemError(errno);
}
+ if (-1 == munmap(nmem, size)) PrintSystemError(errno);
return -1;
}
memcpy(start, tmem, size);
@@ -405,8 +406,10 @@ MoveTextRegionToLargePages(const text_region& r) {
if (ret == -1) {
PrintSystemError(errno);
}
+ if (-1 == munmap(nmem, size)) PrintSystemError(errno);
return -1;
}
+ if (-1 == munmap(nmem, size)) PrintSystemError(errno);
return ret;
}
@@ -418,12 +421,12 @@ int MapStaticCodeToLargePages() {
return -1;
}
-#if defined(__linux__)
+#if defined(__linux__) || defined(__FreeBSD__)
if (r.from > reinterpret_cast<void*>(&MoveTextRegionToLargePages))
return MoveTextRegionToLargePages(r);
return -1;
-#elif defined(__FreeBSD__) || defined(__APPLE__)
+#elif defined(__APPLE__)
return MoveTextRegionToLargePages(r);
#endif
}
diff --git a/src/node.cc b/src/node.cc
index f5ae0159d2..9599b3625a 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -64,9 +64,7 @@
#include "inspector/worker_inspector.h" // ParentInspectorHandle
#endif
-#ifdef NODE_ENABLE_LARGE_CODE_PAGES
#include "large_pages/node_large_page.h"
-#endif
#ifdef NODE_REPORT
#include "node_report.h"
@@ -1000,14 +998,6 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) {
CHECK_GT(argc, 0);
-#ifdef NODE_ENABLE_LARGE_CODE_PAGES
- if (node::IsLargePagesEnabled()) {
- if (node::MapStaticCodeToLargePages() != 0) {
- fprintf(stderr, "Reverting to default page size\n");
- }
- }
-#endif
-
// Hack around with the argv pointer. Used for process.title = "blah".
argv = uv_setup_args(argc, argv);
@@ -1027,6 +1017,26 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) {
}
}
+#if defined(NODE_ENABLE_LARGE_CODE_PAGES) && NODE_ENABLE_LARGE_CODE_PAGES
+ if (per_process::cli_options->use_largepages == "on" ||
+ per_process::cli_options->use_largepages == "silent") {
+ if (node::IsLargePagesEnabled()) {
+ if (node::MapStaticCodeToLargePages() != 0 &&
+ per_process::cli_options->use_largepages != "silent") {
+ fprintf(stderr,
+ "Mapping code to large pages failed. Reverting to default page "
+ "size.\n");
+ }
+ } else if (per_process::cli_options->use_largepages != "silent") {
+ fprintf(stderr, "Large pages are not enabled.\n");
+ }
+ }
+#else
+ if (per_process::cli_options->use_largepages == "on") {
+ fprintf(stderr, "Mapping to large pages is not supported.\n");
+ }
+#endif // NODE_ENABLE_LARGE_CODE_PAGES
+
if (per_process::cli_options->print_version) {
printf("%s\n", NODE_VERSION);
result.exit_code = 0;
diff --git a/src/node_options.cc b/src/node_options.cc
index 622287d524..3a38017e52 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -63,6 +63,11 @@ void PerProcessOptions::CheckOptions(std::vector<std::string>* errors) {
"used, not both");
}
#endif
+ if (use_largepages != "off" &&
+ use_largepages != "on" &&
+ use_largepages != "silent") {
+ errors->push_back("invalid value for --use-largepages");
+ }
per_isolate->CheckOptions(errors);
}
@@ -752,6 +757,10 @@ PerProcessOptionsParser::PerProcessOptionsParser(
kAllowedInEnvironment);
#endif
#endif
+ AddOption("--use-largepages",
+ "Map the Node.js static code to large pages",
+ &PerProcessOptions::use_largepages,
+ kAllowedInEnvironment);
Insert(iop, &PerProcessOptions::get_per_isolate_options);
}
diff --git a/src/node_options.h b/src/node_options.h
index 633d572536..35f0b032d0 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -237,6 +237,7 @@ class PerProcessOptions : public Options {
bool force_fips_crypto = false;
#endif
#endif
+ std::string use_largepages = "off";
#ifdef NODE_REPORT
std::vector<std::string> cmdline;
diff --git a/test/parallel/test-startup-large-pages.js b/test/parallel/test-startup-large-pages.js
new file mode 100644
index 0000000000..d5589ee547
--- /dev/null
+++ b/test/parallel/test-startup-large-pages.js
@@ -0,0 +1,29 @@
+'use strict';
+
+// Make sure that Node.js runs correctly with the --use-largepages option.
+
+require('../common');
+const assert = require('assert');
+const { spawnSync } = require('child_process');
+
+{
+ const child = spawnSync(process.execPath,
+ [ '--use-largepages=on', '-p', '42' ]);
+ const stdout = child.stdout.toString().match(/\S+/g);
+ assert.strictEqual(child.status, 0);
+ assert.strictEqual(child.signal, null);
+ assert.strictEqual(stdout.length, 1);
+ assert.strictEqual(stdout[0], '42');
+}
+
+{
+ const child = spawnSync(process.execPath,
+ [ '--use-largepages=xyzzy', '-p', '42' ]);
+ assert.strictEqual(child.status, 9);
+ assert.strictEqual(child.signal, null);
+ assert.strictEqual(child.stderr.toString().match(/\S+/g).slice(1).join(' '),
+ 'invalid value for --use-largepages');
+}
+
+// TODO(gabrielschulhof): Make assertions about the stderr, which may or may not
+// contain a message indicating that mapping to large pages has failed.