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

v13.10.0 proposal #32027

Merged
merged 91 commits into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
db291aa
doc: guide - using valgrind to debug memory leaks
mhdawson Jan 24, 2020
57302f8
src: prefer 3-argument Array::New()
addaleax Feb 13, 2020
eb2dce8
doc: claim ABI version 82 for Electron 10
MarshallOfSound Feb 13, 2020
f87ac90
worker: unroll file extension regexp
addaleax Feb 13, 2020
9e4aad7
doc: fix typos in doc/api/https.md
Jeff-Tian Feb 14, 2020
b177bba
doc: move @Fishrock123 to a previous releaser
Fishrock123 Feb 10, 2020
7f4d6ee
doc: move @Fishrock123 to TSC Emeriti
Fishrock123 Feb 10, 2020
b071758
doc: pronouns for @Fishrock123
Fishrock123 Feb 10, 2020
f952605
doc: move gireeshpunathil to TSC emeritus
gireeshpunathil Feb 13, 2020
60c71dc
test: add known issue test for sync writable callback
jasnell Feb 12, 2020
3969af4
doc: reword possessive form of Node.js in debugger.md
Trott Feb 12, 2020
cb210e6
doc: reword possessive form of Node.js in process.md
Trott Feb 12, 2020
3eaf377
doc: reword possessive form of Node.js in http.md
Trott Feb 12, 2020
672f76d
doc: reword possessive form of Node.js in adding-new-napi-api.md
Trott Feb 12, 2020
98d262e
src: inform callback scopes about exceptions in HTTP parser
addaleax Feb 14, 2020
724bf31
test: remove common.PORT from test-net-timeout
Trott Feb 12, 2020
e76ac1d
test: remove common.PORT from test-net-throttle
Trott Feb 12, 2020
3fbd5ab
test: remove common.PORT from test-tls-server-large-request
Trott Feb 12, 2020
87e9014
test: remove common.PORT from test-net-pause
Trott Feb 12, 2020
bbb6cc7
module: package "exports" error refinements
guybedford Feb 3, 2020
9079bb4
http2: make compat finished match http/1
ronag Nov 13, 2018
3438937
doc: fix notable changes for v13.9.0
codebytere Feb 18, 2020
94a471a
meta: move eljefedelrodeodeljefe to emeritus
Trott Feb 11, 2020
a86cb0e
vm: lazily initialize primordials for vm contexts
joyeecheung Feb 11, 2020
f2389eb
worker: emit runtime error on loop creation failure
HarshithaKP Feb 3, 2020
1933efa
test: remove common.PORT from test-net-write-callbacks.js
Trott Feb 18, 2020
7d5776e
test: remove flaky designation for test-net-connect-options-port
Trott Feb 18, 2020
f858f23
tools: update lint-md task to lint for possessives of Node.js
Trott Feb 19, 2020
091b4bf
doc: add note about ssh key to releases
codebytere Feb 18, 2020
79b1f04
tools: sync gyp code base with node-gyp repo
targos Nov 20, 2019
61a0d8b
meta: move julianduque to emeritus
Trott Feb 19, 2020
d0e94fc
crypto: fix ieee-p1363 for createVerify
tniessen Feb 20, 2020
2046652
doc: fix anchor for ERR_TLS_INVALID_CONTEXT
tniessen Feb 22, 2020
acb3aff
tls: expose SSL_export_keying_material
simllll Feb 15, 2020
aa16d80
doc,crypto: re-document oaepLabel option
bnoordhuis Feb 17, 2020
4fe9e04
test: remove common.PORT from assorted pummel tests
Trott Feb 21, 2020
4dffd04
cli: --perf-prof only works on Linux
codebytere Feb 21, 2020
877ab97
async_hooks: introduce async-context API
vdeturckheim Mar 1, 2019
15cc9b0
doc: update assert.rejects() docs with a validation function example
MadLittleMods Jan 9, 2020
88ccb44
src: move BaseObject subclass dtors/ctors out of node_crypto.h
addaleax Dec 6, 2019
8fa6373
src: allow unique_ptrs with custom deleter in memory tracker
addaleax Oct 1, 2019
a468392
doc: update releases guide re pushing tags
MylesBorins Feb 18, 2020
9f68e14
src: elevate v8 namespaces
HarshithaKP Feb 21, 2020
b30a698
deps: move zlib maintenance info to guides
sam-github Feb 14, 2020
4c6343f
doc: describe how to update zlib
sam-github Feb 14, 2020
c27f0d1
deps: update zlib to upstream d7f3ca9
sam-github Feb 14, 2020
776f379
src: include large pages source unconditionally
Feb 21, 2020
e08fef1
test: add secp224k1 check in crypto-dh-stateless
danbev Feb 21, 2020
f293dcf
tools: add NODE_TEST_NO_INTERNET to the doc builder
joyeecheung Feb 18, 2020
c5acf0a
doc: updated YAML version representation in readline.md
Trott Feb 23, 2020
ae3929e
vm: implement vm.measureMemory() for per-context memory measurement
joyeecheung Feb 7, 2020
6af9e7e
async_hooks: executionAsyncResource matches in hooks
Flarna Feb 16, 2020
f89fb27
test: mark empty udp tests flaky on OS X
sam-github Feb 24, 2020
b74c40e
meta: move not-an-aardvark to emeritus
Trott Feb 24, 2020
918c2b6
test: fix typo in common/index.js
Trott Feb 24, 2020
04eda02
test: add documentation for common.enoughTestCpu
Trott Feb 24, 2020
b9f3bfe
module: disable conditional exports, self resolve warnings
guybedford Feb 18, 2020
f62967c
src: enable `StreamPipe` for generic `StreamBase`s
addaleax Mar 12, 2018
8516602
doc: clarify http2.connect authority details
jasnell Feb 17, 2020
e3258fd
doc: update zlib doc
jasnell Feb 6, 2020
6adbfac
repl: eager-evaluate input in parens
codebytere Feb 25, 2020
49c959d
test: increase timeout in vm-timeout-escape-queuemicrotask
lundibundi Feb 26, 2020
ab8f060
test: fix usage of invalid common properties
lundibundi Feb 24, 2020
f1e7648
test: validate common property usage
lundibundi Feb 24, 2020
ca44071
build: add missing comma in node.gyp
cjihrig Feb 26, 2020
3497370
src: move InternalCallbackScope to StartExecution
codebytere Feb 25, 2020
f71fc90
async_hooks: add store arg in AsyncLocalStorage
puzpuzpuz Feb 24, 2020
d0a0071
stream: invoke buffered write callbacks on error
ronag Nov 22, 2019
6a35b0d
src: don't run bootstrapper in CreateEnvironment
codebytere Feb 22, 2020
9e3e676
module: port source map sort logic from chromium
bcoe Feb 24, 2020
cef5502
test: remove sequential/test-https-keep-alive-large-write.js
rustyconover Jan 27, 2020
b6d33f6
test: change test to not be sensitive to buffer send size
rustyconover Feb 26, 2020
2c0b249
tls: reduce memory copying and number of BIO buffer allocations
rustyconover Jan 24, 2020
4d05508
crypto: turn impossible DH errors into assertions
tniessen Feb 24, 2020
8ad64b8
stream: support passing generator functions into pipeline()
ronag Jan 6, 2020
313ecaa
stream: fix broken pipeline error propagation
ronag Feb 21, 2020
8a2b62e
stream: ensure pipeline always destroys streams
ronag Feb 24, 2020
e6125cd
deps: V8: backport f7771e5b0cc4
mmarchini Feb 26, 2020
91ce69a
meta: move Glen Keane to Collaborator Emeritus
Trott Feb 28, 2020
ded3890
meta: move maclover7 to Emeritus
Trott Feb 28, 2020
c801045
meta: move jbergstroem to emeritus
Trott Feb 28, 2020
3bd8fea
meta: move aqrln to emeritus
Trott Feb 28, 2020
3849474
test: fix flaky test-gc-net-timeout
ronag Feb 22, 2020
9a41ced
build: only lint markdown files that have changed (POSIX-only)
Trott Feb 23, 2020
166579f
doc: add link to sem-ver info
rosaxxny Feb 27, 2020
49864d1
test: fix flaky test-dns-any.js
Trott Feb 29, 2020
cd30dbb
doc: revise --zero-fill-buffers text in buffer.md
Trott Feb 29, 2020
9325634
test: improve disable AsyncLocalStorage test
puzpuzpuz Feb 28, 2020
fbaab7d
deps: openssl: cherry-pick 4dcb150ea30f
AdamMajer Feb 28, 2020
1bca7b6
test: move test-inspector-module to parallel
Trott Feb 29, 2020
f6ffdc2
2020-03-04 Version 13.10.0 (Current)
codebytere Feb 29, 2020
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
Prev Previous commit
Next Next commit
vm: implement vm.measureMemory() for per-context memory measurement
This patch implements `vm.measureMemory()` with the new
`v8::Isolate::MeasureMemory()` API to measure per-context memory
usage. This should be experimental, since detailed memory
measurement requires further integration with the V8 API
that should be available in a future V8 update.

PR-URL: #31824
Refs: https://github.com/ulan/performance-measure-memory
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
joyeecheung authored and codebytere committed Feb 27, 2020
commit ae3929e958dfa72bcf9f9efeb53c89f825c228ce
8 changes: 8 additions & 0 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,14 @@ STDERR/STDOUT, and the data's length is longer than the `maxBuffer` option.
`Console` was instantiated without `stdout` stream, or `Console` has a
non-writable `stdout` or `stderr` stream.

<a id="ERR_CONTEXT_NOT_INITIALIZED"></a>
### `ERR_CONTEXT_NOT_INITIALIZED`

The vm context passed into the API is not yet initialized. This could happen
when an error occurs (and is caught) during the creation of the
context, for example, when the allocation fails or the maximum call stack
size is reached when the context is created.

<a id="ERR_CONSTRUCT_CALL_REQUIRED"></a>
### `ERR_CONSTRUCT_CALL_REQUIRED`

Expand Down
50 changes: 50 additions & 0 deletions doc/api/vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,56 @@ console.log(globalVar);
// 1000
```

## `vm.measureMemory([options])`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental

Measure the memory known to V8 and used by the current execution context
or a specified context.

* `options` {Object} Optional.
* `mode` {string} Either `'summary'` or `'detailed'`.
**Default:** `'summary'`
* `context` {Object} Optional. A [contextified][] object returned
by `vm.createContext()`. If not specified, measure the memory
usage of the current context where `vm.measureMemory()` is invoked.
* Returns: {Promise} If the memory is successfully measured the promise will
resolve with an object containing information about the memory usage.

The format of the object that the returned Promise may resolve with is
specific to the V8 engine and may change from one version of V8 to the next.

The returned result is different from the statistics returned by
`v8.getHeapSpaceStatistics()` in that `vm.measureMemory()` measures
the memory reachable by V8 from a specific context, while
`v8.getHeapSpaceStatistics()` measures the memory used by an instance
of V8 engine, which can switch among multiple contexts that reference
objects in the heap of one engine.

```js
const vm = require('vm');
// Measure the memory used by the current context and return the result
// in summary.
vm.measureMemory({ mode: 'summary' })
// Is the same as vm.measureMemory()
.then((result) => {
// The current format is:
// { total: { jsMemoryEstimate: 2211728, jsMemoryRange: [ 0, 2211728 ] } }
console.log(result);
});

const context = vm.createContext({});
vm.measureMemory({ mode: 'detailed' }, context)
.then((result) => {
// At the moment the detailed format is the same as the summary one.
console.log(result);
});
```

## Class: `vm.Module`
<!-- YAML
added: v13.0.0
Expand Down
1 change: 1 addition & 0 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ E('ERR_CHILD_PROCESS_STDIO_MAXBUFFER', '%s maxBuffer length exceeded',
RangeError);
E('ERR_CONSOLE_WRITABLE_STREAM',
'Console expects a writable stream instance for %s', TypeError);
E('ERR_CONTEXT_NOT_INITIALIZED', 'context used is not initialized', Error);
E('ERR_CPU_USAGE', 'Unable to obtain cpu usage %s', Error);
E('ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
'Custom engines not supported by this OpenSSL', Error);
Expand Down
37 changes: 35 additions & 2 deletions lib/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,21 @@ const {
ArrayIsArray,
ArrayPrototypeForEach,
Symbol,
PromiseReject
} = primordials;

const {
ContextifyScript,
makeContext,
isContext: _isContext,
compileFunction: _compileFunction
constants,
compileFunction: _compileFunction,
measureMemory: _measureMemory,
} = internalBinding('contextify');
const {
ERR_CONTEXT_NOT_INITIALIZED,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
} = require('internal/errors').codes;
const {
isArrayBufferView,
Expand All @@ -44,7 +49,10 @@ const {
validateUint32,
validateString
} = require('internal/validators');
const { kVmBreakFirstLineSymbol } = require('internal/util');
const {
kVmBreakFirstLineSymbol,
emitExperimentalWarning,
} = require('internal/util');
const kParsingContext = Symbol('script parsing context');

class Script extends ContextifyScript {
Expand Down Expand Up @@ -401,6 +409,30 @@ function compileFunction(code, params, options = {}) {
return result.function;
}

const measureMemoryModes = {
summary: constants.measureMemory.mode.SUMMARY,
detailed: constants.measureMemory.mode.DETAILED,
};

function measureMemory(options = {}) {
emitExperimentalWarning('vm.measureMemory');
validateObject(options, 'options');
const { mode = 'summary', context } = options;
if (mode !== 'summary' && mode !== 'detailed') {
throw new ERR_INVALID_ARG_VALUE(
'options.mode', options.mode,
'must be either \'summary\' or \'detailed\'');
}
if (context !== undefined &&
(typeof context !== 'object' || context === null || !_isContext(context))) {
throw new ERR_INVALID_ARG_TYPE('options.context', 'vm.Context', context);
}
const result = _measureMemory(measureMemoryModes[mode], context);
if (result === undefined) {
return PromiseReject(new ERR_CONTEXT_NOT_INITIALIZED());
}
return result;
}

module.exports = {
Script,
Expand All @@ -411,6 +443,7 @@ module.exports = {
runInThisContext,
isContext,
compileFunction,
measureMemory,
};

if (require('internal/options').getOptionValue('--experimental-vm-modules')) {
Expand Down
44 changes: 44 additions & 0 deletions src/node_contextify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,20 @@ using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::IndexedPropertyHandlerConfiguration;
using v8::Int32;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Maybe;
using v8::MaybeLocal;
using v8::MeasureMemoryMode;
using v8::Name;
using v8::NamedPropertyHandlerConfiguration;
using v8::Number;
using v8::Object;
using v8::ObjectTemplate;
using v8::PrimitiveArray;
using v8::Promise;
using v8::PropertyAttribute;
using v8::PropertyCallbackInfo;
using v8::PropertyDescriptor;
Expand Down Expand Up @@ -1203,11 +1206,39 @@ static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(ret);
}

static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsInt32());
int32_t mode = args[0].As<v8::Int32>()->Value();
Isolate* isolate = args.GetIsolate();
Environment* env = Environment::GetCurrent(args);
Local<Context> context;
if (args[1]->IsUndefined()) {
context = isolate->GetCurrentContext();
} else {
CHECK(args[1]->IsObject());
ContextifyContext* sandbox =
ContextifyContext::ContextFromContextifiedSandbox(env,
args[1].As<Object>());
CHECK_NOT_NULL(sandbox);
context = sandbox->context();
if (context.IsEmpty()) { // Not yet fully initilaized
return;
}
}
v8::Local<v8::Promise> promise;
if (!isolate->MeasureMemory(context, static_cast<v8::MeasureMemoryMode>(mode))
.ToLocal(&promise)) {
return;
}
args.GetReturnValue().Set(promise);
}

void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Environment* env = Environment::GetCurrent(context);
Isolate* isolate = env->isolate();
ContextifyContext::Init(env, target);
ContextifyScript::Init(env, target);

Expand All @@ -1224,6 +1255,19 @@ void Initialize(Local<Object> target,

env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
}

Local<Object> constants = Object::New(env->isolate());
Local<Object> measure_memory = Object::New(env->isolate());
Local<Object> memory_mode = Object::New(env->isolate());
MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
READONLY_PROPERTY(measure_memory, "mode", memory_mode);
READONLY_PROPERTY(constants, "measureMemory", measure_memory);
target->Set(context, env->constants_string(), constants).Check();

env->SetMethod(target, "measureMemory", MeasureMemory);
}

} // namespace contextify
Expand Down
70 changes: 70 additions & 0 deletions test/parallel/test-vm-measure-memory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const vm = require('vm');

common.expectWarning('ExperimentalWarning',
'vm.measureMemory is an experimental feature. ' +
'This feature could change at any time');

// The formats could change when V8 is updated, then the tests should be
// updated accordingly.
function assertSummaryShape(result) {
assert.strictEqual(typeof result, 'object');
assert.strictEqual(typeof result.total, 'object');
assert.strictEqual(typeof result.total.jsMemoryEstimate, 'number');
assert(Array.isArray(result.total.jsMemoryRange));
assert.strictEqual(typeof result.total.jsMemoryRange[0], 'number');
assert.strictEqual(typeof result.total.jsMemoryRange[1], 'number');
}

function assertDetailedShape(result) {
// For now, the detailed shape is the same as the summary shape. This
// should change in future versions of V8.
return assertSummaryShape(result);
}

// Test measuring memory of the current context
{
vm.measureMemory()
.then(assertSummaryShape);

vm.measureMemory({})
.then(assertSummaryShape);

vm.measureMemory({ mode: 'summary' })
.then(assertSummaryShape);

vm.measureMemory({ mode: 'detailed' })
.then(assertDetailedShape);

assert.throws(() => vm.measureMemory(null), {
code: 'ERR_INVALID_ARG_TYPE'
});
assert.throws(() => vm.measureMemory('summary'), {
code: 'ERR_INVALID_ARG_TYPE'
});
assert.throws(() => vm.measureMemory({ mode: 'random' }), {
code: 'ERR_INVALID_ARG_VALUE'
});
}

// Test measuring memory of the sandbox
{
const context = vm.createContext();
vm.measureMemory({ context })
.then(assertSummaryShape);

vm.measureMemory({ mode: 'summary', context },)
.then(assertSummaryShape);

vm.measureMemory({ mode: 'detailed', context })
.then(assertDetailedShape);

assert.throws(() => vm.measureMemory({ mode: 'summary', context: null }), {
code: 'ERR_INVALID_ARG_TYPE'
});
assert.throws(() => vm.measureMemory({ mode: 'summary', context: {} }), {
code: 'ERR_INVALID_ARG_TYPE'
});
}