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

core: implement resourceUsage() #1568

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 34 additions & 0 deletions doc/api/process.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,40 @@ a diff reading, useful for benchmarks and measuring intervals:
}, 1000);


## process.resourceUsage()

Returns the resource usage measures.

Note: Windows only provides the following resource usage measures - all others
are filled with zero:

- `userCpuTimeUsedSec`
- `userCpuTimeUsedMs`
- `systemCpuTimeUsedSec`
- `systemCpuTimeUsedMs`

An example output looks like this:

{ userCpuTimeUsedSec: 0,
userCpuTimeUsedMs: 159729,
systemCpuTimeUsedSec: 0,
systemCpuTimeUsedMs: 30597,
maxResidentSetSize: 20426752,
sharedMemSize: 0,
integralUnsharedDataSize: 0,
integralUnsharedStackSize: 0,
pageReclaims: 3002,
pageFaults: 2250,
swaps: 0,
blockInputOperations: 0,
blockOutputOperations: 0,
ipcMessagesSent: 55,
ipcMessagesReceived: 54,
signalsReceived: 0,
voluntaryContextSwitches: 92,
involuntaryContextSwitches: 374 }


## process.mainModule

Alternate way to retrieve
Expand Down
18 changes: 18 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,24 @@ namespace node {
V(write_queue_size_string, "writeQueueSize") \
V(x_forwarded_string, "x-forwarded-for") \
V(zero_return_string, "ZERO_RETURN") \
V(user_cpu_time_used_sec, "userCpuTimeUsedSec") \
V(user_cpu_time_used_ms, "userCpuTimeUsedMs") \
V(system_cpu_time_used_sec, "systemCpuTimeUsedSec") \
V(system_cpu_time_used_ms, "systemCpuTimeUsedMs") \
V(max_resident_set_size, "maxResidentSetSize") \
V(integral_shared_mem_size, "sharedMemSize") \
V(integral_unshared_data_size, "integralUnsharedDataSize") \
V(integral_unshared_stack_size, "integralUnsharedStackSize") \
V(page_reclaims, "pageReclaims") \
V(page_faults, "pageFaults") \
V(swaps, "swaps") \
V(block_input_operations, "blockInputOperations") \
V(block_output_operations, "blockOutputOperations") \
V(ipc_messages_sent, "ipcMessagesSent") \
V(ipc_messages_received, "ipcMessagesReceived") \
V(signals_received, "signalsReceived") \
V(voluntary_context_switches, "voluntaryContextSwitches") \
V(involuntary_context_switches, "involuntaryContextSwitches") \

#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
V(as_external, v8::External) \
Expand Down
52 changes: 52 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1923,6 +1923,56 @@ static void Uptime(const FunctionCallbackInfo<Value>& args) {
}


static void GetResourceUsage(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

uv_rusage_t rusage;
int err = uv_getrusage(&rusage);
if (err)
return env->ThrowUVException(err, "uv_getrusage");

Local<Object> resource_usage = Object::New(env->isolate());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer this be implemented the same way fs.Stat was implemented (https:/iojs/io.js/blob/7dc8eec/lib/fs.js#L105-L134).

@bnoordhuis Do this in another PR, or take care of it in this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Virtual shrug. I don't think it really matters here.

fs.stat() gets called thousands of times at start-up so it makes sense to optimize it to death. This getrusage() wrapper is not nearly as performance sensitive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay. we'll wait for feedback about performance before we do something else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bnoordhuis @trevnorris
What if someone was to query resource stats on a regular basis (like 1/500ms), i.e. to build a graph? In that case the overhead of passing the args back the normal way would have considerable perf impact right?
And the only upside to doing it the less performant way is slightly less ugly code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convince me with numbers. I speculate that the largest cost center is the actual getrusage() system call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thlorenz @bnoordhuis Usually the first iteration of this process.resourceUsage is the slowest with 0.042276ms, but other iterations take ~0.019789ms - the lowest of my iterations was around ~0.011ms. Compared to the first os.freemem() (just as an example for a function that calls every time the libuv function) call with 0.026139ms other calls are around ~0.009892ms. All numbers are measured using the js functions.

resource_usage->Set(env->user_cpu_time_used_sec(),
Number::New(env->isolate(), rusage.ru_utime.tv_sec));
resource_usage->Set(env->user_cpu_time_used_ms(),
Number::New(env->isolate(), rusage.ru_utime.tv_usec));
resource_usage->Set(env->system_cpu_time_used_sec(),
Number::New(env->isolate(), rusage.ru_stime.tv_sec));
resource_usage->Set(env->system_cpu_time_used_ms(),
Number::New(env->isolate(), rusage.ru_stime.tv_usec));
resource_usage->Set(env->max_resident_set_size(),
Number::New(env->isolate(), rusage.ru_maxrss));
resource_usage->Set(env->integral_shared_mem_size(),
Number::New(env->isolate(), rusage.ru_ixrss));
resource_usage->Set(env->integral_unshared_data_size(),
Number::New(env->isolate(), rusage.ru_idrss));
resource_usage->Set(env->integral_unshared_stack_size(),
Number::New(env->isolate(), rusage.ru_isrss));
resource_usage->Set(env->page_reclaims(),
Number::New(env->isolate(), rusage.ru_minflt));
resource_usage->Set(env->page_faults(),
Number::New(env->isolate(), rusage.ru_majflt));
resource_usage->Set(env->swaps(),
Number::New(env->isolate(), rusage.ru_nswap));
resource_usage->Set(env->block_input_operations(),
Number::New(env->isolate(), rusage.ru_inblock));
resource_usage->Set(env->block_output_operations(),
Number::New(env->isolate(), rusage.ru_oublock));
resource_usage->Set(env->ipc_messages_sent(),
Number::New(env->isolate(), rusage.ru_msgsnd));
resource_usage->Set(env->ipc_messages_received(),
Number::New(env->isolate(), rusage.ru_msgrcv));
resource_usage->Set(env->signals_received(),
Number::New(env->isolate(), rusage.ru_nsignals));
resource_usage->Set(env->voluntary_context_switches(),
Number::New(env->isolate(), rusage.ru_nvcsw));
resource_usage->Set(env->involuntary_context_switches(),
Number::New(env->isolate(), rusage.ru_nivcsw));

args.GetReturnValue().Set(resource_usage);
}


void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Expand Down Expand Up @@ -2839,6 +2889,8 @@ void SetupProcessObject(Environment* env,

env->SetMethod(process, "hrtime", Hrtime);

env->SetMethod(process, "resourceUsage", GetResourceUsage);

env->SetMethod(process, "dlopen", DLOpen);

env->SetMethod(process, "uptime", Uptime);
Expand Down
23 changes: 23 additions & 0 deletions test/sequential/test-resource-usage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var assert = require('assert');
var common = require('../common');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linter is probably going to complain that this should have 'use strict' at the top and that the imports should be const.



const usage = process.resourceUsage();

assert(usage.userCpuTimeUsedSec >= 0);
assert(usage.userCpuTimeUsedMs >= 0);
assert(usage.systemCpuTimeUsedSec >= 0);
assert(usage.systemCpuTimeUsedMs >= 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you test for the presence of all fields here?

assert(usage.maxResidentSetSize >= 0);
assert(usage.sharedMemSize >= 0);
assert(usage.integralUnsharedDataSize >= 0);
assert(usage.integralUnsharedStackSize >= 0);
assert(usage.pageReclaims >= 0);
assert(usage.pageFaults >= 0);
assert(usage.swaps >= 0);
assert(usage.blockInputOperations >= 0);
assert(usage.blockOutputOperations >= 0);
assert(usage.ipcMessagesSent >= 0);
assert(usage.ipcMessagesReceived >= 0);
assert(usage.voluntaryContextSwitches >= 0);
assert(usage.involuntaryContextSwitches >= 0);