Skip to content

Commit 19f9281

Browse files
vmarchaudtargos
authored andcommitted
process: expose uv_rusage on process.resourcesUsage()
As discussed in nodejs/diagnostics#161, the core should expose important metrics about the runtime, this PR's goal is to let user get the number of io request made, and lower level mertrics like the page faults and context switches. PR-URL: #28018 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 624fd17 commit 19f9281

File tree

5 files changed

+176
-1
lines changed

5 files changed

+176
-1
lines changed

doc/api/process.md

+89
Original file line numberDiff line numberDiff line change
@@ -1815,6 +1815,91 @@ process.report.writeReport();
18151815

18161816
Additional documentation is available in the [report documentation][].
18171817

1818+
## process.resourceUsage()
1819+
<!-- YAML
1820+
added: REPLACEME
1821+
-->
1822+
1823+
* Returns: {Object}
1824+
* `userCPUTime` {integer}
1825+
* `systemCPUTime` {integer}
1826+
* `maxRSS` {integer}
1827+
* `sharedMemorySize` {integer}
1828+
* `unsharedDataSize` {integer}
1829+
* `unsharedStackSize` {integer}
1830+
* `minorPageFault` {integer}
1831+
* `majorPageFault` {integer}
1832+
* `swapedOut` {integer}
1833+
* `fsRead` {integer}
1834+
* `fsWrite` {integer}
1835+
* `ipcSent` {integer}
1836+
* `ipcReceived` {integer}
1837+
* `signalsCount` {integer}
1838+
* `voluntaryContextSwitches` {integer}
1839+
* `involuntaryContextSwitches` {integer}
1840+
1841+
The `process.resourceUsage()` method returns the resource usage
1842+
for the current process.
1843+
All of these values come from the `uv_getrusage` call which returns
1844+
[this struct][uv_rusage_t], here the mapping between node and libuv:
1845+
- `userCPUTime` maps to `ru_utime` computed in microseconds.
1846+
It is the values as [`process.cpuUsage().user`][process.cpuUsage]
1847+
- `systemCPUTime` maps to `ru_stime` computed in microseconds.
1848+
It is the value as [`process.cpuUsage().system`][process.cpuUsage]
1849+
- `maxRSS` maps to `ru_maxrss` which is the maximum resident set size
1850+
used (in kilobytes).
1851+
- `sharedMemorySize` maps to `ru_ixrss` but is not supported by any platform.
1852+
- `unsharedDataSize` maps to `ru_idrss` but is not supported by any platform.
1853+
- `unsharedStackSize` maps to `ru_isrss` but is not supported by any platform.
1854+
- `minorPageFault` maps to `ru_minflt` which is the number of minor page fault
1855+
for the process, see [this article for more details][wikipedia_minor_fault]
1856+
- `majorPageFault` maps to `ru_majflt` which is the number of major page fault
1857+
for the process, see [this article for more details][wikipedia_major_fault].
1858+
This field is not supported on Windows platforms.
1859+
- `swappedOut` maps to `ru_nswap` which is not supported by any platform.
1860+
- `fsRead` maps to `ru_inblock` which is the number of times the file system
1861+
had to perform input.
1862+
- `fsWrite` maps to `ru_oublock` which is the number of times the file system
1863+
had to perform output.
1864+
- `ipcSent` maps to `ru_msgsnd` but is not supported by any platform.
1865+
- `ipcReceived` maps to `ru_msgrcv` but is not supported by any platform.
1866+
- `signalsCount` maps to `ru_nsignals` but is not supported by any platform.
1867+
- `voluntaryContextSwitches` maps to `ru_nvcsw` which is the number of times
1868+
a CPU context switch resulted due to a process voluntarily giving up the
1869+
processor before its time slice was completed
1870+
(usually to await availability of a resource).
1871+
This field is not supported on Windows platforms.
1872+
- `involuntaryContextSwitches` maps to `ru_nivcsw` which is the number of times
1873+
a CPU context switch resulted due to a higher priority process becoming runnable
1874+
or because the current process exceeded its time slice.
1875+
This field is not supported on Windows platforms.
1876+
1877+
1878+
```js
1879+
console.log(process.resourceUsage());
1880+
/*
1881+
Will output:
1882+
{
1883+
userCPUTime: 82872,
1884+
systemCPUTime: 4143,
1885+
maxRSS: 33164,
1886+
sharedMemorySize: 0,
1887+
unsharedDataSize: 0,
1888+
unsharedStackSize: 0,
1889+
minorPageFault: 2469,
1890+
majorPageFault: 0,
1891+
swapedOut: 0,
1892+
fsRead: 0,
1893+
fsWrite: 8,
1894+
ipcSent: 0,
1895+
ipcReceived: 0,
1896+
signalsCount: 0,
1897+
voluntaryContextSwitches: 79,
1898+
involuntaryContextSwitches: 1
1899+
}
1900+
*/
1901+
```
1902+
18181903
## process.send(message[, sendHandle[, options]][, callback])
18191904
<!-- YAML
18201905
added: v0.5.9
@@ -2329,6 +2414,10 @@ cases:
23292414
[Writable]: stream.html#stream_writable_streams
23302415
[debugger]: debugger.html
23312416
[note on process I/O]: process.html#process_a_note_on_process_i_o
2417+
[process.cpuUsage]: #process_process_cpuusage_previousvalue
23322418
[process_emit_warning]: #process_process_emitwarning_warning_type_code_ctor
23332419
[process_warning]: #process_event_warning
23342420
[report documentation]: report.html
2421+
[uv_rusage_t]: http://docs.libuv.org/en/v1.x/misc.html#c.uv_rusage_t
2422+
[wikipedia_minor_fault]: https://en.wikipedia.org/wiki/Page_fault#Minor
2423+
[wikipedia_major_fault]: https://en.wikipedia.org/wiki/Page_fault#Major

lib/internal/bootstrap/node.js

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ if (isMainThread) {
110110
process.hrtime = wrapped.hrtime;
111111
process.hrtime.bigint = wrapped.hrtimeBigInt;
112112
process.cpuUsage = wrapped.cpuUsage;
113+
process.resourceUsage = wrapped.resourceUsage;
113114
process.memoryUsage = wrapped.memoryUsage;
114115
process.kill = wrapped.kill;
115116
process.exit = wrapped.exit;

lib/internal/process/per_thread.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ function wrapProcessMethods(binding) {
3535
hrtime: _hrtime,
3636
hrtimeBigInt: _hrtimeBigInt,
3737
cpuUsage: _cpuUsage,
38-
memoryUsage: _memoryUsage
38+
memoryUsage: _memoryUsage,
39+
resourceUsage: _resourceUsage
3940
} = binding;
4041

4142
function _rawDebug(...args) {
@@ -190,12 +191,36 @@ function wrapProcessMethods(binding) {
190191
return true;
191192
}
192193

194+
const resourceValues = new Float64Array(16);
195+
function resourceUsage() {
196+
_resourceUsage(resourceValues);
197+
return {
198+
userCPUTime: resourceValues[0],
199+
systemCPUTime: resourceValues[1],
200+
maxRSS: resourceValues[2],
201+
sharedMemorySize: resourceValues[3],
202+
unsharedDataSize: resourceValues[4],
203+
unsharedStackSize: resourceValues[5],
204+
minorPageFault: resourceValues[6],
205+
majorPageFault: resourceValues[7],
206+
swappedOut: resourceValues[8],
207+
fsRead: resourceValues[9],
208+
fsWrite: resourceValues[10],
209+
ipcSent: resourceValues[11],
210+
ipcReceived: resourceValues[12],
211+
signalsCount: resourceValues[13],
212+
voluntaryContextSwitches: resourceValues[14],
213+
involuntaryContextSwitches: resourceValues[15]
214+
};
215+
}
216+
193217

194218
return {
195219
_rawDebug,
196220
hrtime,
197221
hrtimeBigInt,
198222
cpuUsage,
223+
resourceUsage,
199224
memoryUsage,
200225
kill,
201226
exit

src/node_process_methods.cc

+33
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,38 @@ void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
278278
Array::New(env->isolate(), handle_v.data(), handle_v.size()));
279279
}
280280

281+
static void ResourceUsage(const FunctionCallbackInfo<Value>& args) {
282+
Environment* env = Environment::GetCurrent(args);
283+
284+
uv_rusage_t rusage;
285+
int err = uv_getrusage(&rusage);
286+
if (err)
287+
return env->ThrowUVException(err, "uv_getrusage");
288+
289+
CHECK(args[0]->IsFloat64Array());
290+
Local<Float64Array> array = args[0].As<Float64Array>();
291+
CHECK_EQ(array->Length(), 16);
292+
Local<ArrayBuffer> ab = array->Buffer();
293+
double* fields = static_cast<double*>(ab->GetContents().Data());
294+
295+
fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
296+
fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
297+
fields[2] = rusage.ru_maxrss;
298+
fields[3] = rusage.ru_ixrss;
299+
fields[4] = rusage.ru_idrss;
300+
fields[5] = rusage.ru_isrss;
301+
fields[6] = rusage.ru_minflt;
302+
fields[7] = rusage.ru_majflt;
303+
fields[8] = rusage.ru_nswap;
304+
fields[9] = rusage.ru_inblock;
305+
fields[10] = rusage.ru_oublock;
306+
fields[11] = rusage.ru_msgsnd;
307+
fields[12] = rusage.ru_msgrcv;
308+
fields[13] = rusage.ru_nsignals;
309+
fields[14] = rusage.ru_nvcsw;
310+
fields[15] = rusage.ru_nivcsw;
311+
}
312+
281313
#ifdef __POSIX__
282314
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
283315
Environment* env = Environment::GetCurrent(args);
@@ -418,6 +450,7 @@ static void InitializeProcessMethods(Local<Object> target,
418450
env->SetMethod(target, "cpuUsage", CPUUsage);
419451
env->SetMethod(target, "hrtime", Hrtime);
420452
env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
453+
env->SetMethod(target, "resourceUsage", ResourceUsage);
421454

422455
env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
423456
env->SetMethod(target, "_getActiveHandles", GetActiveHandles);

test/parallel/test-resource-usage.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
require('../common');
3+
const assert = require('assert');
4+
5+
const rusage = process.resourceUsage();
6+
7+
[
8+
'userCPUTime',
9+
'systemCPUTime',
10+
'maxRSS',
11+
'sharedMemorySize',
12+
'unsharedDataSize',
13+
'unsharedStackSize',
14+
'minorPageFault',
15+
'majorPageFault',
16+
'swappedOut',
17+
'fsRead',
18+
'fsWrite',
19+
'ipcSent',
20+
'ipcReceived',
21+
'signalsCount',
22+
'voluntaryContextSwitches',
23+
'involuntaryContextSwitches'
24+
].forEach((n) => {
25+
assert.strictEqual(typeof rusage[n], 'number', `${n} should be a number`);
26+
assert(rusage[n] >= 0, `${n} should be above or equal 0`);
27+
});

0 commit comments

Comments
 (0)