Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
ab150d7
test: remove flakiness on macOS test
anonrig Feb 9, 2025
0a82d27
test: reduce flakiness on test-net-write-fully-async-buffer
anonrig Feb 9, 2025
d0ee8c0
src: improve error handling in process_wrap
jasnell Feb 11, 2025
41f444f
src: improve error handling in string_bytes/decoder
jasnell Feb 11, 2025
d8e70dc
src: improve node::Dotenv trimming
dario-piotrowicz Feb 11, 2025
9b98ac6
test: update WPT for urlpattern to ef6d83d789
nodejs-github-bot Feb 12, 2025
2990cc8
doc: run license-builder
github-actions[bot] Feb 12, 2025
35f89aa
build: fix GN build of uv
zcbenz Feb 12, 2025
3bc6d62
doc: add `signal` to `filehandle.writeFile()` options
y-hsgw Feb 12, 2025
7e2dac9
src: add self-assigment memcpy checks
wooffie Feb 12, 2025
a6b7bce
doc: move stability index after history section for consistency
aduh95 Feb 12, 2025
a9112df
tools: add support for `import source` syntax in linter
aduh95 Feb 12, 2025
c011271
doc: update cleanup to trust on vuln db automation
RafaelGSS Feb 13, 2025
18ea88b
crypto: cleanup root certificates and skip PEM deserialization
joyeecheung Feb 13, 2025
2ec4ff1
meta: update last name for jkrems
hybrist Feb 13, 2025
dfdaa92
crypto: fix missing OPENSSL_NO_ENGINE guard
codebytere Feb 14, 2025
1efd74b
tools: fix release URL computation in update-root-certs.mjs
joyeecheung Feb 14, 2025
44dd8a5
doc: buffer: fix typo on `Buffer.copyBytesFrom(` `offset` option
tpoisseau Feb 14, 2025
6951133
doc: improve documentation on argument validation
Aditi-1400 Feb 14, 2025
b369ad6
test: remove unnecessary assert requiring from tests
dario-piotrowicz Feb 14, 2025
ccb8c12
test,crypto: make tests work for BoringSSL
codebytere Feb 15, 2025
5af35d1
build: fix GN build failure
zcbenz Feb 15, 2025
50ba04e
doc: recommend writing tests in new files and including comments
joyeecheung Feb 15, 2025
6cdee54
tools: do not run major-release workflow on forks
Trott Feb 15, 2025
a588066
test: add case for unrecognised fields within pjson "exports"
JakobJingleheimer Feb 13, 2025
40f3a51
fs: handle UV_ENOTDIR in `fs.statSync` with `throwIfNoEntry` provided
juanarbol Feb 10, 2025
5b2dfad
doc: add a note about `require('../common')` in testing documentation
Aditi-1400 Feb 15, 2025
b50fc42
crypto: support --use-system-ca on non-Windows and non-macOS
joyeecheung Feb 15, 2025
fa26f83
src: lock the isolate properly in IsolateData destructor
joyeecheung Feb 15, 2025
286bb84
src: fix accessing empty string
zcbenz Feb 16, 2025
c02494f
doc: fix transpiler loader hooks documentation
joyeecheung Feb 16, 2025
a7e5ef9
doc: fix wrong verb form
dario-piotrowicz Feb 16, 2025
9de45cb
doc: `modules.md`: fix `distance` definition
alexweej Feb 16, 2025
f4a82fd
benchmark: add a warmup on bench-openSync
elvessilvavieira Feb 16, 2025
ed5671f
doc: update `module.builtinModules` sentence
dario-piotrowicz Feb 16, 2025
78d4e52
doc: fix wrong articles used to address modules
dario-piotrowicz Feb 17, 2025
4b02fdc
doc: update Xcode version used for arm64 and pkg
targos Feb 17, 2025
5414eb4
src: improve error handling in multiple files
jasnell Feb 8, 2025
90875ba
src: improve error handling in node_blob
jasnell Feb 15, 2025
46df14d
doc: update clang-cl on Windows building guide
joyeecheung Feb 18, 2025
fec2d50
build: add skip_apidoc_files and include QUIC
RafaelGSS Feb 6, 2025
ac35106
sea: suppress builtin warning with disableExperimentalSEAWarning option
koooge Feb 16, 2025
5a74568
doc: disambiguate pseudo-code statement
dario-piotrowicz Feb 18, 2025
cc1cafd
module: allow omitting context in synchronous next hooks
joyeecheung Feb 18, 2025
21d795a
dns: add TLSA record query and parsing
rithvikvibhu May 14, 2024
0de128c
doc: add `module namespace object` links
dario-piotrowicz Feb 16, 2025
b696049
doc: fix link and history of `SourceMap` sections
aduh95 Feb 18, 2025
56f9fe7
src: port `defineLazyProperties` to native code
aduh95 Feb 18, 2025
e3127b8
src: replace NewFromUtf8 with OneByteString where appropriate
jasnell Feb 18, 2025
2929fc6
test_runner: allow special characters in snapshot keys
Ceres6 Feb 19, 2025
b384baa
build: print 'Formatting Markdown...' for long task markdown formatting
1ilsang Feb 19, 2025
e26d484
cli: allow --cpu-prof* in NODE_OPTIONS
Ceres6 Feb 20, 2025
73a8514
tools: consolidate 'introduced_in' check for docs
1ilsang Feb 20, 2025
fdc8aeb
doc: fix 'introduced_in' version in typescript module
1ilsang Feb 20, 2025
7dd326e
src: move instead of copy shared pointer in node_blob
targos Feb 20, 2025
e0a91f6
src: gate all quic behind disabled-by-default compile flag
jasnell Feb 19, 2025
d62299b
meta: add CODEOWNERS for SQLite
cjihrig Feb 20, 2025
90a4de0
src: do not format single string argument for THROW_ERR_*
joyeecheung Feb 18, 2025
ad3c572
module: improve error message from asynchronicity in require(esm)
joyeecheung Feb 17, 2025
8421021
deps: update ada to 3.1.0
nodejs-github-bot Feb 20, 2025
ccf496c
test: improve error output of test-http2-client-promisify-connect-error
aduh95 Feb 21, 2025
c6ddfa5
process: add threadCpuUsage
ShogunPanda Feb 21, 2025
d922153
url: improve urlpattern regexp performance
anonrig Feb 21, 2025
c6d6be2
typings: fix `ImportModuleDynamicallyCallback` return type
legendecas Feb 21, 2025
315244e
test: simplify test-http2-client-promisify-connect-error
lpinca Feb 22, 2025
587112c
doc: remove buffered flag from performance hooks examples
pavel-romanov8 Feb 23, 2025
85ac02f
meta: bump `github/codeql-action` from 3.27.5 to 3.28.8
dependabot[bot] Feb 23, 2025
7f5f02b
meta: bump `actions/stale` from 9.0.0 to 9.1.0
dependabot[bot] Feb 23, 2025
dfd42db
meta: bump `actions/cache` from 4.1.2 to 4.2.0
dependabot[bot] Feb 23, 2025
58d7036
meta: bump `step-security/harden-runner` from 2.10.2 to 2.10.4
dependabot[bot] Feb 23, 2025
0dd0108
meta: bump `codecov/codecov-action` from 5.0.7 to 5.3.1
dependabot[bot] Feb 23, 2025
3d61604
meta: bump `mozilla-actions/sccache-action` from 0.0.6 to 0.0.7
dependabot[bot] Feb 23, 2025
35cdd9b
meta: bump `peter-evans/create-pull-request` from 7.0.5 to 7.0.6
dependabot[bot] Feb 23, 2025
f77069b
meta: bump `actions/setup-python` from 5.3.0 to 5.4.0
dependabot[bot] Feb 23, 2025
d6234b4
inspector: skip promise hook in the inspector async hook
joyeecheung Feb 23, 2025
a025d7b
tools: run Linux tests on GitHub arm64 runners as well
dennisameling Feb 23, 2025
ef314dc
src: fix crash when lazy getter is invoked in a vm context
legendecas Feb 23, 2025
66614cf
doc: fix web.libera.chat link in pull-requests.md
SamB Feb 23, 2025
7c7e9f4
test: make eval snapshot comparison more flexible
codebytere Feb 23, 2025
51dff8b
test: fix test-without-async-context-frame.mjs in debug mode
joyeecheung Feb 15, 2025
116c1fe
test_runner: refactor testPlan counter increse
pmarchini Feb 23, 2025
4413ce7
doc: fix typo in Windows building instructions
timja Feb 24, 2025
e10ef27
inspector: convert event params to protocol without json
legendecas Feb 24, 2025
f35bd86
doc: add additional caveat for fs.watch
mhdawson Feb 24, 2025
1a24417
test: add doAppendAndCancel test
y-hsgw Feb 24, 2025
455bf5a
doc: update options to filehandle.appendFile()
y-hsgw Feb 24, 2025
e08d7d4
lib: fixup incorrect argument order in assertEncoding
jasnell Feb 22, 2025
aa81785
lib: fixup more incorrect ERR_INVALID_ARG_VALUE uses
jasnell Feb 23, 2025
2aceca1
deps: update sqlite to 3.49.1
nodejs-github-bot Feb 25, 2025
8644cf3
deps: update ngtcp2 to 1.11.0
nodejs-github-bot Feb 25, 2025
8076284
deps: update cjs-module-lexer to 2.1.0
nodejs-github-bot Feb 25, 2025
9d2368f
2025-02-26, Version 23.9.0 (Current)
nodejs-github-bot Feb 25, 2025
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
process: add threadCpuUsage
PR-URL: #56467
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
ShogunPanda authored and targos committed Feb 25, 2025
commit c6ddfa52fb9f9a9cf37dee12104aa2ee27ffb00f
19 changes: 19 additions & 0 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -4204,6 +4204,25 @@ Thrown:
[DeprecationWarning: test] { name: 'DeprecationWarning' }
```

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

<!-- YAML
added: REPLACEME
-->

* `previousValue` {Object} A previous return value from calling
`process.cpuUsage()`
* Returns: {Object}
* `user` {integer}
* `system` {integer}

The `process.threadCpuUsage()` method returns the user and system CPU time usage of
the current worker thread, in an object with properties `user` and `system`, whose
values are microsecond values (millionth of a second).

The result of a previous call to `process.threadCpuUsage()` can be passed as the
argument to the function, to get a diff reading.

## `process.title`

<!-- YAML
Expand Down
1 change: 1 addition & 0 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ const rawMethods = internalBinding('process_methods');
process.loadEnvFile = wrapped.loadEnvFile;
process._rawDebug = wrapped._rawDebug;
process.cpuUsage = wrapped.cpuUsage;
process.threadCpuUsage = wrapped.threadCpuUsage;
process.resourceUsage = wrapped.resourceUsage;
process.memoryUsage = wrapped.memoryUsage;
process.constrainedMemory = rawMethods.constrainedMemory;
Expand Down
47 changes: 47 additions & 0 deletions lib/internal/process/per_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const {
codes: {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_OPERATION_FAILED,
ERR_OUT_OF_RANGE,
ERR_UNKNOWN_SIGNAL,
},
Expand Down Expand Up @@ -97,6 +98,7 @@ function nop() {}
function wrapProcessMethods(binding) {
const {
cpuUsage: _cpuUsage,
threadCpuUsage: _threadCpuUsage,
memoryUsage: _memoryUsage,
rss,
resourceUsage: _resourceUsage,
Expand Down Expand Up @@ -148,6 +150,50 @@ function wrapProcessMethods(binding) {
};
}

const threadCpuValues = new Float64Array(2);

// Replace the native function with the JS version that calls the native
// function.
function threadCpuUsage(prevValue) {
// If a previous value was passed in, ensure it has the correct shape.
if (prevValue) {
if (!previousValueIsValid(prevValue.user)) {
validateObject(prevValue, 'prevValue');

validateNumber(prevValue.user, 'prevValue.user');
throw new ERR_INVALID_ARG_VALUE.RangeError('prevValue.user',
prevValue.user);
}

if (!previousValueIsValid(prevValue.system)) {
validateNumber(prevValue.system, 'prevValue.system');
throw new ERR_INVALID_ARG_VALUE.RangeError('prevValue.system',
prevValue.system);
}
}

if (process.platform === 'sunos') {
throw new ERR_OPERATION_FAILED('threadCpuUsage is not available on SunOS');
}

// Call the native function to get the current values.
_threadCpuUsage(threadCpuValues);

// If a previous value was passed in, return diff of current from previous.
if (prevValue) {
return {
user: threadCpuValues[0] - prevValue.user,
system: threadCpuValues[1] - prevValue.system,
};
}

// If no previous value passed in, return current value.
return {
user: threadCpuValues[0],
system: threadCpuValues[1],
};
}

// Ensure that a previously passed in value is valid. Currently, the native
// implementation always returns numbers <= Number.MAX_SAFE_INTEGER.
function previousValueIsValid(num) {
Expand Down Expand Up @@ -263,6 +309,7 @@ function wrapProcessMethods(binding) {
return {
_rawDebug,
cpuUsage,
threadCpuUsage,
resourceUsage,
memoryUsage,
kill,
Expand Down
25 changes: 25 additions & 0 deletions src/node_process_methods.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,29 @@ static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
}

// ThreadCPUUsage use libuv's uv_getrusage_thread() this-thread resource usage
// accessor, to access ru_utime (user CPU time used) and ru_stime
// (system CPU time used), which are uv_timeval_t structs
// (long tv_sec, long tv_usec).
// Returns those values as Float64 microseconds in the elements of the array
// passed to the function.
static void ThreadCPUUsage(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
uv_rusage_t rusage;

// Call libuv to get the values we'll return.
int err = uv_getrusage_thread(&rusage);
if (err) return env->ThrowUVException(err, "uv_getrusage_thread");

// Get the double array pointer from the Float64Array argument.
Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 2);
double* fields = static_cast<double*>(ab->Data());

// Set the Float64Array elements to be user / system values in microseconds.
fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
}

static void Cwd(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->has_run_bootstrapping_code());
Expand Down Expand Up @@ -651,6 +674,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
SetMethod(isolate, target, "availableMemory", GetAvailableMemory);
SetMethod(isolate, target, "rss", Rss);
SetMethod(isolate, target, "cpuUsage", CPUUsage);
SetMethod(isolate, target, "threadCpuUsage", ThreadCPUUsage);
SetMethod(isolate, target, "resourceUsage", ResourceUsage);

SetMethod(isolate, target, "_debugEnd", DebugEnd);
Expand Down Expand Up @@ -695,6 +719,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(GetAvailableMemory);
registry->Register(Rss);
registry->Register(CPUUsage);
registry->Register(ThreadCPUUsage);
registry->Register(ResourceUsage);

registry->Register(GetActiveRequests);
Expand Down
87 changes: 87 additions & 0 deletions test/parallel/test-process-threadCpuUsage-main-thread.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use strict';

const { isSunOS } = require('../common');

const { ok, throws, notStrictEqual } = require('assert');

function validateResult(result) {
notStrictEqual(result, null);

ok(Number.isFinite(result.user));
ok(Number.isFinite(result.system));

ok(result.user >= 0);
ok(result.system >= 0);
}

// Test that process.threadCpuUsage() works on the main thread
// The if check and the else branch should be removed once SmartOS support is fixed in
// https://github.com/libuv/libuv/issues/4706
if (!isSunOS) {
const result = process.threadCpuUsage();

// Validate the result of calling with no previous value argument.
validateResult(process.threadCpuUsage());

// Validate the result of calling with a previous value argument.
validateResult(process.threadCpuUsage(result));

// Ensure the results are >= the previous.
let thisUsage;
let lastUsage = process.threadCpuUsage();
for (let i = 0; i < 10; i++) {
thisUsage = process.threadCpuUsage();
validateResult(thisUsage);
ok(thisUsage.user >= lastUsage.user);
ok(thisUsage.system >= lastUsage.system);
lastUsage = thisUsage;
}
} else {
throws(
() => process.threadCpuUsage(),
{
code: 'ERR_OPERATION_FAILED',
name: 'Error',
message: 'Operation failed: threadCpuUsage is not available on SunOS'
}
);
}

// Test argument validaton
{
throws(
() => process.threadCpuUsage(123),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "prevValue" argument must be of type object. Received type number (123)'
}
);

throws(
() => process.threadCpuUsage([]),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "prevValue" argument must be of type object. Received an instance of Array'
}
);

throws(
() => process.threadCpuUsage({ user: -123 }),
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'RangeError',
message: "The property 'prevValue.user' is invalid. Received -123"
}
);

throws(
() => process.threadCpuUsage({ user: 0, system: 'bar' }),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: "The \"prevValue.system\" property must be of type number. Received type string ('bar')"
}
);
}
91 changes: 91 additions & 0 deletions test/parallel/test-process-threadCpuUsage-worker-threads.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict';

const { mustCall, platformTimeout, hasCrypto, skip, isSunOS } = require('../common');

if (!hasCrypto) {
skip('missing crypto');
};

// This block can be removed once SmartOS support is fixed in
// https://github.com/libuv/libuv/issues/4706
// The behavior on SunOS is tested in
// test/parallel/test-process-threadCpuUsage-main-thread.js
if (isSunOS) {
skip('Operation not supported yet on SmartOS');
}

const { ok } = require('assert');
const { randomBytes, createHash } = require('crypto');
const { once } = require('events');
const { Worker, parentPort, workerData } = require('worker_threads');

const FREQUENCIES = [100, 500, 1000];

function performLoad() {
const buffer = randomBytes(1e8);

// Do some work
return setInterval(() => {
createHash('sha256').update(buffer).end(buffer);
}, platformTimeout(workerData?.frequency ?? 100));
}

function getUsages() {
return { process: process.cpuUsage(), thread: process.threadCpuUsage() };
}

function validateResults(results) {
// This test should have checked that the CPU usage of each thread is greater
// than the previous one, while the process one was not.
// Unfortunately, the real values are not really predictable on the CI so we
// just check that all the values are positive numbers.
for (let i = 0; i < 3; i++) {
ok(typeof results[i].process.user === 'number');
ok(results[i].process.user >= 0);

ok(typeof results[i].process.system === 'number');
ok(results[i].process.system >= 0);

ok(typeof results[i].thread.user === 'number');
ok(results[i].thread.user >= 0);

ok(typeof results[i].thread.system === 'number');
ok(results[i].thread.system >= 0);
}
}

// The main thread will spawn three more threads, then after a while it will ask all of them to
// report the thread CPU usage and exit.
if (!workerData?.frequency) { // Do not use isMainThread here otherwise test will not run in --worker mode
const workers = [];
for (const frequency of FREQUENCIES) {
workers.push(new Worker(__filename, { workerData: { frequency } }));
}

setTimeout(mustCall(async () => {
clearInterval(interval);

const results = [getUsages()];

for (const worker of workers) {
const statusPromise = once(worker, 'message');

worker.postMessage('done');
const [status] = await statusPromise;
results.push(status);
worker.terminate();
}

validateResults(results);
}), platformTimeout(5000));

} else {
parentPort.on('message', () => {
clearInterval(interval);
parentPort.postMessage(getUsages());
process.exit(0);
});
}

// Perform load on each thread
const interval = performLoad();
2 changes: 2 additions & 0 deletions typings/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { FsDirBinding } from './internalBinding/fs_dir';
import { MessagingBinding } from './internalBinding/messaging';
import { OptionsBinding } from './internalBinding/options';
import { OSBinding } from './internalBinding/os';
import { ProcessBinding } from './internalBinding/process';
import { SerdesBinding } from './internalBinding/serdes';
import { SymbolsBinding } from './internalBinding/symbols';
import { TimersBinding } from './internalBinding/timers';
Expand All @@ -34,6 +35,7 @@ interface InternalBindingMap {
modules: ModulesBinding;
options: OptionsBinding;
os: OSBinding;
process: ProcessBinding;
serdes: SerdesBinding;
symbols: SymbolsBinding;
timers: TimersBinding;
Expand Down
15 changes: 15 additions & 0 deletions typings/internalBinding/process.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
interface CpuUsageValue {
user: number;
system: number;
}

declare namespace InternalProcessBinding {
interface Process {
cpuUsage(previousValue?: CpuUsageValue): CpuUsageValue;
threadCpuUsage(previousValue?: CpuUsageValue): CpuUsageValue;
}
}

export interface ProcessBinding {
process: InternalProcessBinding.Process;
}