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

src: make --use-largepages a runtime option #30954

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 0 additions & 33 deletions configure.py
Expand Up @@ -404,17 +404,6 @@
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',
Expand Down Expand Up @@ -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']

Expand Down
10 changes: 10 additions & 0 deletions doc/api/cli.md
Expand Up @@ -863,6 +863,15 @@ environment variables.

See `SSL_CERT_DIR` and `SSL_CERT_FILE`.

### `--use-largepages`
<!-- 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.

### `--v8-options`
<!-- YAML
added: v0.1.3
Expand Down Expand Up @@ -1119,6 +1128,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`
Expand Down
5 changes: 5 additions & 0 deletions doc/node.1
Expand Up @@ -398,6 +398,11 @@ See
and
.Ev SSL_CERT_FILE .
.
.It Fl -use-largepages
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.
.
.It Fl -v8-options
Print V8 command-line options.
.
Expand Down
2 changes: 1 addition & 1 deletion node.gyp
Expand Up @@ -833,7 +833,7 @@
}],
],
}],
[ 'node_use_large_pages=="true" and OS in "linux freebsd mac"', {
[ 'OS in "linux freebsd mac"', {
'defines': [ 'NODE_ENABLE_LARGE_CODE_PAGES=1' ],
# The current implementation of Large Pages is under Linux.
# Other implementations are possible but not currently supported.
Expand Down
6 changes: 2 additions & 4 deletions node.gypi
Expand Up @@ -308,17 +308,15 @@
}],
[ '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)',
]
}],
[ '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)',
Expand Down
6 changes: 3 additions & 3 deletions src/large_pages/node_large_page.cc
Expand Up @@ -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;
Expand Down Expand Up @@ -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__)
Expand Down Expand Up @@ -352,7 +352,7 @@ MoveTextRegionToLargePages(const text_region& r) {
return -1;
}

ret = madvise(tmem, size, MADV_HUGEPAGE);
ret = madvise(tmem, size, 14 /* MADV_HUGEPAGE */);
devnexen marked this conversation as resolved.
Show resolved Hide resolved
if (ret == -1) {
PrintSystemError(errno);
ret = munmap(tmem, size);
Expand Down
18 changes: 8 additions & 10 deletions src/node.cc
Expand Up @@ -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"
Expand Down Expand Up @@ -967,14 +965,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);

Expand All @@ -994,6 +984,14 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) {
}
}

if (per_process::cli_options->use_largepages) {
if (node::IsLargePagesEnabled()) {
gabrielschulhof marked this conversation as resolved.
Show resolved Hide resolved
if (node::MapStaticCodeToLargePages() != 0) {
fprintf(stderr, "Reverting to default page size\n");
gabrielschulhof marked this conversation as resolved.
Show resolved Hide resolved
gabrielschulhof marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

if (per_process::cli_options->print_version) {
printf("%s\n", NODE_VERSION);
result.exit_code = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/node_options.cc
Expand Up @@ -748,6 +748,10 @@ PerProcessOptionsParser::PerProcessOptionsParser(
kAllowedInEnvironment);
#endif
#endif
AddOption("--use-largepages",
lundibundi marked this conversation as resolved.
Show resolved Hide resolved
"Map the Node.js static code to large pages",
&PerProcessOptions::use_largepages,
kAllowedInEnvironment);

Insert(iop, &PerProcessOptions::get_per_isolate_options);
}
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Expand Up @@ -235,6 +235,7 @@ class PerProcessOptions : public Options {
bool force_fips_crypto = false;
#endif
#endif
bool use_largepages = false;

#ifdef NODE_REPORT
std::vector<std::string> cmdline;
Expand Down
19 changes: 19 additions & 0 deletions test/parallel/test-startup-large-pages.js
@@ -0,0 +1,19 @@
'use strict';

// A sanity check: Make sure that Node.js runs correctly when running with the
gabrielschulhof marked this conversation as resolved.
Show resolved Hide resolved
// --use-largepages option.

require('../common');
const assert = require('assert');
const { spawnSync } = require('child_process');

const child = spawnSync(process.execPath, [ '--use-largepages', '-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');

// TODO(gabrielschulhof): Make assertions about the stderr, which may or may not
// contain a message indicating that mapping to large pages has failed.