Skip to content

Commit

Permalink
src,lib: add constrainedMemory API for process
Browse files Browse the repository at this point in the history
  • Loading branch information
theanarkh committed Jan 16, 2023
1 parent 5d50b84 commit 262ae5e
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 3 deletions.
20 changes: 20 additions & 0 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,25 @@ and [Cluster][] documentation), the `process.connected` property will return
Once `process.connected` is `false`, it is no longer possible to send messages
over the IPC channel using `process.send()`.

## `process.constrainedMemory()`

<!-- YAML
added: REPLACEME
-->

* {number}

Gets the amount of memory available to the process (in bytes) based on
limits imposed by the OS. If there is no such constraint, or the constraint
is unknown, `0` is returned.

It is not unusual for this value to be less than or greater than `os.totalmem()`.
This function currently only returns a non-zero value on Linux, based on cgroups
if it is present, and on z/OS based on `RLIMIT_MEMLIMIT`.

See [`uv_get_constrained_memory`][uv_get_constrained_memory] for more
information.

## `process.cpuUsage([previousValue])`

<!-- YAML
Expand Down Expand Up @@ -3901,6 +3920,7 @@ cases:
[process_warning]: #event-warning
[report documentation]: report.md
[terminal raw mode]: tty.md#readstreamsetrawmodemode
[uv_get_constrained_memory]: https://docs.libuv.org/en/v1.x/misc.html#c.uv_get_constrained_memory
[uv_rusage_t]: https://docs.libuv.org/en/v1.x/misc.html#c.uv_rusage_t
[wikipedia_major_fault]: https://en.wikipedia.org/wiki/Page_fault#Major
[wikipedia_minor_fault]: https://en.wikipedia.org/wiki/Page_fault#Minor
1 change: 1 addition & 0 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ const rawMethods = internalBinding('process_methods');

process.hrtime = perThreadSetup.hrtime;
process.hrtime.bigint = perThreadSetup.hrtimeBigInt;
process.constrainedMemory = perThreadSetup.constrainedMemory;

process.openStdin = function() {
process.stdin.resume();
Expand Down
12 changes: 12 additions & 0 deletions lib/internal/process/per_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const binding = internalBinding('process_methods');

let hrValues;
let hrBigintValues;
let constrainedMemoryValues;

function refreshHrtimeBuffer() {
// The 3 entries filled in by the original process.hrtime contains
Expand All @@ -71,8 +72,12 @@ function refreshHrtimeBuffer() {
hrBigintValues = new BigUint64Array(binding.hrtimeBuffer, 0, 1);
}

function refreshConstrainedMemoryValuesBuffer() {
constrainedMemoryValues = new BigUint64Array(binding.hrtimeBuffer, 0, 1);
}
// Create the buffers.
refreshHrtimeBuffer();
refreshConstrainedMemoryValuesBuffer();

function hrtime(time) {
binding.hrtime();
Expand Down Expand Up @@ -100,6 +105,11 @@ function hrtimeBigInt() {
return hrBigintValues[0];
}

function constrainedMemory() {
binding.constrainedMemory();
return constrainedMemoryValues[0];
}

function nop() {}

// The execution of this function itself should not cause any side effects.
Expand Down Expand Up @@ -427,4 +437,6 @@ module.exports = {
hrtime,
hrtimeBigInt,
refreshHrtimeBuffer,
refreshConstrainedMemoryValuesBuffer,
constrainedMemory,
};
6 changes: 3 additions & 3 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ function refreshRuntimeOptions() {
function patchProcessObject(expandArgv1) {
const binding = internalBinding('process_methods');
binding.patchProcessObject(process);

require('internal/process/per_thread').refreshHrtimeBuffer();

const perThread = require('internal/process/per_thread');
perThread.refreshHrtimeBuffer();
perThread.refreshConstrainedMemoryValuesBuffer();
ObjectDefineProperty(process, 'argv0', {
__proto__: null,
enumerable: true,
Expand Down
6 changes: 6 additions & 0 deletions src/node_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ class BindingData : public SnapshotableObject {

static void SlowBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);

static void ConstrainedMemoryImpl(BindingData* receiver);
static void SlowGetConstrainedMemory(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void FastGetConstrainedMemory(v8::Local<v8::Value> receiver);

private:
static constexpr size_t kBufferSize =
std::max(sizeof(uint64_t), sizeof(uint32_t) * 3);
Expand All @@ -92,6 +97,7 @@ class BindingData : public SnapshotableObject {
// time.
static v8::CFunction fast_number_;
static v8::CFunction fast_bigint_;
static v8::CFunction fast_get_constrained_memory_;
};

} // namespace process
Expand Down
27 changes: 27 additions & 0 deletions src/node_process_methods.cc
Original file line number Diff line number Diff line change
Expand Up @@ -471,11 +471,18 @@ BindingData::BindingData(Environment* env, v8::Local<v8::Object> object)

v8::CFunction BindingData::fast_number_(v8::CFunction::Make(FastNumber));
v8::CFunction BindingData::fast_bigint_(v8::CFunction::Make(FastBigInt));
v8::CFunction BindingData::fast_get_constrained_memory_ =
v8::CFunction::Make(FastGetConstrainedMemory);

void BindingData::AddMethods() {
Local<Context> ctx = env()->context();
SetFastMethod(ctx, object(), "hrtime", SlowNumber, &fast_number_);
SetFastMethod(ctx, object(), "hrtimeBigInt", SlowBigInt, &fast_bigint_);
SetFastMethod(ctx,
object(),
"constrainedMemory",
SlowGetConstrainedMemory,
&fast_get_constrained_memory_);
}

void BindingData::RegisterExternalReferences(
Expand All @@ -486,6 +493,9 @@ void BindingData::RegisterExternalReferences(
registry->Register(FastBigInt);
registry->Register(fast_number_.GetTypeInfo());
registry->Register(fast_bigint_.GetTypeInfo());
registry->Register(SlowGetConstrainedMemory);
registry->Register(FastGetConstrainedMemory);
registry->Register(fast_get_constrained_memory_.GetTypeInfo());
}

BindingData* BindingData::FromV8Value(Local<Value> value) {
Expand Down Expand Up @@ -533,6 +543,23 @@ void BindingData::SlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args) {
NumberImpl(FromJSObject<BindingData>(args.Holder()));
}

void BindingData::ConstrainedMemoryImpl(BindingData* receiver) {
// Make sure we don't accidentally access buffers wiped for snapshot.
CHECK(!receiver->array_buffer_.IsEmpty());
uint64_t t = uv_get_constrained_memory();
uint64_t* fields = static_cast<uint64_t*>(receiver->backing_store_->Data());
fields[0] = t;
}

void BindingData::SlowGetConstrainedMemory(
const FunctionCallbackInfo<Value>& args) {
ConstrainedMemoryImpl(FromJSObject<BindingData>(args.Holder()));
}

void BindingData::FastGetConstrainedMemory(v8::Local<v8::Value> receiver) {
ConstrainedMemoryImpl(FromV8Value(receiver));
}

bool BindingData::PrepareForSerialization(Local<Context> context,
v8::SnapshotCreator* creator) {
// It's not worth keeping.
Expand Down
12 changes: 12 additions & 0 deletions test/sequential/test-process-constrained-memory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';
require('../common');
const assert = require('assert');
const { Worker } = require('worker_threads');

if (!process.env.isWorker) {
process.env.isWorker = true;
new Worker(__filename);
assert(process.constrainedMemory() >= 0);
} else {
assert(process.constrainedMemory() >= 0);
}

0 comments on commit 262ae5e

Please sign in to comment.