Browse Source

process: improve memoryUsage() performance

Creating an object in JS and using a typed array to transfer values
from C++ to JS is faster than creating an object and setting
properties in C++.

The included benchmark shows ~34% increase in performance with this
change.

PR-URL: https://github.com/nodejs/node/pull/11497
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
v6.x
Brian White 8 years ago
committed by Myles Borins
parent
commit
b7088a9355
No known key found for this signature in database GPG Key ID: 933B01F40B5CA946
  1. 16
      benchmark/process/memoryUsage.js
  2. 1
      lib/internal/bootstrap_node.js
  3. 15
      lib/internal/process.js
  4. 4
      src/env.h
  5. 31
      src/node.cc

16
benchmark/process/memoryUsage.js

@ -0,0 +1,16 @@
'use strict';
var common = require('../common.js');
var bench = common.createBenchmark(main, {
n: [1e5]
});
function main(conf) {
var n = +conf.n;
bench.start();
for (var i = 0; i < n; i++) {
process.memoryUsage();
}
bench.end(n);
}

1
lib/internal/bootstrap_node.js

@ -48,6 +48,7 @@
_process.setup_hrtime(); _process.setup_hrtime();
_process.setup_cpuUsage(); _process.setup_cpuUsage();
_process.setupMemoryUsage();
_process.setupConfig(NativeModule._source); _process.setupConfig(NativeModule._source);
NativeModule.require('internal/process/warning').setup(); NativeModule.require('internal/process/warning').setup();
NativeModule.require('internal/process/next_tick').setup(); NativeModule.require('internal/process/next_tick').setup();

15
lib/internal/process.js

@ -11,6 +11,7 @@ function lazyConstants() {
exports.setup_cpuUsage = setup_cpuUsage; exports.setup_cpuUsage = setup_cpuUsage;
exports.setup_hrtime = setup_hrtime; exports.setup_hrtime = setup_hrtime;
exports.setupMemoryUsage = setupMemoryUsage;
exports.setupConfig = setupConfig; exports.setupConfig = setupConfig;
exports.setupKillAndExit = setupKillAndExit; exports.setupKillAndExit = setupKillAndExit;
exports.setupSignalHandlers = setupSignalHandlers; exports.setupSignalHandlers = setupSignalHandlers;
@ -100,6 +101,20 @@ function setup_hrtime() {
}; };
} }
function setupMemoryUsage() {
const memoryUsage_ = process.memoryUsage;
const memValues = new Float64Array(4);
process.memoryUsage = function memoryUsage() {
memoryUsage_(memValues);
return {
rss: memValues[0],
heapTotal: memValues[1],
heapUsed: memValues[2],
external: memValues[3]
};
};
}
function setupConfig(_source) { function setupConfig(_source) {
// NativeModule._source // NativeModule._source

4
src/env.h

@ -105,7 +105,6 @@ namespace node {
V(exponent_string, "exponent") \ V(exponent_string, "exponent") \
V(exports_string, "exports") \ V(exports_string, "exports") \
V(ext_key_usage_string, "ext_key_usage") \ V(ext_key_usage_string, "ext_key_usage") \
V(external_string, "external") \
V(external_stream_string, "_externalStream") \ V(external_stream_string, "_externalStream") \
V(family_string, "family") \ V(family_string, "family") \
V(fatal_exception_string, "_fatalException") \ V(fatal_exception_string, "_fatalException") \
@ -115,8 +114,6 @@ namespace node {
V(flags_string, "flags") \ V(flags_string, "flags") \
V(gid_string, "gid") \ V(gid_string, "gid") \
V(handle_string, "handle") \ V(handle_string, "handle") \
V(heap_total_string, "heapTotal") \
V(heap_used_string, "heapUsed") \
V(homedir_string, "homedir") \ V(homedir_string, "homedir") \
V(hostmaster_string, "hostmaster") \ V(hostmaster_string, "hostmaster") \
V(ignore_string, "ignore") \ V(ignore_string, "ignore") \
@ -184,7 +181,6 @@ namespace node {
V(rename_string, "rename") \ V(rename_string, "rename") \
V(replacement_string, "replacement") \ V(replacement_string, "replacement") \
V(retry_string, "retry") \ V(retry_string, "retry") \
V(rss_string, "rss") \
V(serial_string, "serial") \ V(serial_string, "serial") \
V(scopeid_string, "scopeid") \ V(scopeid_string, "scopeid") \
V(sent_shutdown_string, "sentShutdown") \ V(sent_shutdown_string, "sentShutdown") \

31
src/node.cc

@ -2290,25 +2290,22 @@ void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
return env->ThrowUVException(err, "uv_resident_set_memory"); return env->ThrowUVException(err, "uv_resident_set_memory");
} }
Isolate* isolate = env->isolate();
// V8 memory usage // V8 memory usage
HeapStatistics v8_heap_stats; HeapStatistics v8_heap_stats;
env->isolate()->GetHeapStatistics(&v8_heap_stats); isolate->GetHeapStatistics(&v8_heap_stats);
Local<Number> heap_total = // Get the double array pointer from the Float64Array argument.
Number::New(env->isolate(), v8_heap_stats.total_heap_size()); CHECK(args[0]->IsFloat64Array());
Local<Number> heap_used = Local<Float64Array> array = args[0].As<Float64Array>();
Number::New(env->isolate(), v8_heap_stats.used_heap_size()); CHECK_EQ(array->Length(), 4);
Local<Number> external_mem = Local<ArrayBuffer> ab = array->Buffer();
Number::New(env->isolate(), double* fields = static_cast<double*>(ab->GetContents().Data());
env->isolate()->AdjustAmountOfExternalAllocatedMemory(0));
fields[0] = rss;
Local<Object> info = Object::New(env->isolate()); fields[1] = v8_heap_stats.total_heap_size();
info->Set(env->rss_string(), Number::New(env->isolate(), rss)); fields[2] = v8_heap_stats.used_heap_size();
info->Set(env->heap_total_string(), heap_total); fields[3] = isolate->AdjustAmountOfExternalAllocatedMemory(0);
info->Set(env->heap_used_string(), heap_used);
info->Set(env->external_string(), external_mem);
args.GetReturnValue().Set(info);
} }

Loading…
Cancel
Save