Browse Source

node: improve GetActiveRequests performance

v8 is faster at setting object properties in JS than C++. Even when it
requires calling into JS from native code. Make
process._getActiveRequests() faster by doing this when populating the
array containing request objects.

Simple benchmark:

    for (let i = 0; i < 22; i++)
      fs.open(__filename, 'r', function() { });
    let t = process.hrtime();
    for (let i = 0; i < 1e6; i++)
      process._getActiveRequests();
    t = process.hrtime(t);
    console.log((t[0] * 1e9 + t[1]) / 1e6);

Results between the two:

    Previous:  4406 ns/op
    Patched:    690 ns/op     5.4x faster

PR-URL: https://github.com/nodejs/node/pull/3375
Reviewed-By: James Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <ben@strongloop.com>
process-exit-stdio-flushing
Trevor Norris 9 years ago
parent
commit
494227bb03
  1. 1
      src/env.h
  2. 39
      src/node.cc
  3. 11
      src/node.js
  4. 10
      test/parallel/test-process-getactiverequests.js

1
src/env.h

@ -227,6 +227,7 @@ namespace node {
V(zero_return_string, "ZERO_RETURN") \
#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
V(add_properties_by_index_function, v8::Function) \
V(as_external, v8::External) \
V(async_hooks_init_function, v8::Function) \
V(async_hooks_pre_function, v8::Function) \

39
src/node.cc

@ -1009,6 +1009,17 @@ void RunMicrotasks(const FunctionCallbackInfo<Value>& args) {
}
void SetupProcessObject(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsFunction());
env->set_add_properties_by_index_function(args[0].As<Function>());
env->process_object()->Delete(
FIXED_ONE_BYTE_STRING(env->isolate(), "_setupProcessObject"));
}
void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@ -1546,11 +1557,30 @@ static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Local<Array> ary = Array::New(args.GetIsolate());
int i = 0;
Local<Context> ctx = env->context();
Local<Function> fn = env->add_properties_by_index_function();
static const size_t argc = 8;
Local<Value> argv[argc];
size_t i = 0;
for (auto w : *env->req_wrap_queue()) {
if (w->persistent().IsEmpty() == false) {
argv[i++ % argc] = w->object();
if ((i % argc) == 0) {
HandleScope scope(env->isolate());
fn->Call(ctx, ary, argc, argv).ToLocalChecked();
for (auto&& arg : argv) {
arg = Local<Value>();
}
}
}
}
for (auto w : *env->req_wrap_queue())
if (w->persistent().IsEmpty() == false)
ary->Set(i++, w->object());
const size_t remainder = i % argc;
if (remainder > 0) {
HandleScope scope(env->isolate());
fn->Call(ctx, ary, remainder, argv).ToLocalChecked();
}
args.GetReturnValue().Set(ary);
}
@ -2979,6 +3009,7 @@ void SetupProcessObject(Environment* env,
env->SetMethod(process, "binding", Binding);
env->SetMethod(process, "_linkedBinding", LinkedBinding);
env->SetMethod(process, "_setupProcessObject", SetupProcessObject);
env->SetMethod(process, "_setupNextTick", SetupNextTick);
env->SetMethod(process, "_setupPromises", SetupPromises);
env->SetMethod(process, "_setupDomainUse", SetupDomainUse);

11
src/node.js

@ -22,6 +22,8 @@
process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated
startup.setupProcessObject();
// do this good and early, since it handles errors.
startup.processFatal();
@ -173,6 +175,15 @@
}
}
startup.setupProcessObject = function() {
process._setupProcessObject(setPropByIndex);
function setPropByIndex() {
for (var i = 0; i < arguments.length; i++)
this.push(arguments[i]);
}
};
startup.globalVariables = function() {
global.process = process;
global.global = global;

10
test/parallel/test-process-getactiverequests.js

@ -0,0 +1,10 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const fs = require('fs');
for (let i = 0; i < 12; i++)
fs.open(__filename, 'r', function() { });
assert.equal(12, process._getActiveRequests().length);
Loading…
Cancel
Save