Browse Source

os: improve cpus() performance

PR-URL: https://github.com/nodejs/node/pull/11564
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jackson Tian <shyvo1987@gmail.com>
v7.x
Brian White 8 years ago
committed by Anna Henningsen
parent
commit
e2133f3e57
No known key found for this signature in database GPG Key ID: D8B9F5AEAE84E4CF
  1. 17
      benchmark/os/cpus.js
  2. 23
      lib/os.js
  3. 58
      src/node_os.cc
  4. 6
      src/node_util.cc

17
benchmark/os/cpus.js

@ -0,0 +1,17 @@
'use strict';
const common = require('../common.js');
const cpus = require('os').cpus;
const bench = common.createBenchmark(main, {
n: [3e4]
});
function main(conf) {
const n = +conf.n;
bench.start();
for (var i = 0; i < n; ++i)
cpus();
bench.end(n);
}

23
lib/os.js

@ -1,7 +1,9 @@
'use strict'; 'use strict';
const binding = process.binding('os'); const binding = process.binding('os');
const getCPUs = binding.getCPUs;
const getLoadAvg = binding.getLoadAvg; const getLoadAvg = binding.getLoadAvg;
const pushValToArrayMax = process.binding('util').pushValToArrayMax;
const constants = process.binding('constants').os; const constants = process.binding('constants').os;
const internalUtil = require('internal/util'); const internalUtil = require('internal/util');
const isWindows = process.platform === 'win32'; const isWindows = process.platform === 'win32';
@ -10,7 +12,6 @@ exports.hostname = binding.getHostname;
exports.uptime = binding.getUptime; exports.uptime = binding.getUptime;
exports.freemem = binding.getFreeMem; exports.freemem = binding.getFreeMem;
exports.totalmem = binding.getTotalMem; exports.totalmem = binding.getTotalMem;
exports.cpus = binding.getCPUs;
exports.type = binding.getOSType; exports.type = binding.getOSType;
exports.release = binding.getOSRelease; exports.release = binding.getOSRelease;
exports.networkInterfaces = binding.getInterfaceAddresses; exports.networkInterfaces = binding.getInterfaceAddresses;
@ -23,6 +24,26 @@ exports.loadavg = function loadavg() {
return [avgValues[0], avgValues[1], avgValues[2]]; return [avgValues[0], avgValues[1], avgValues[2]];
}; };
const cpuValues = new Float64Array(6 * pushValToArrayMax);
function addCPUInfo() {
for (var i = 0, c = 0; i < arguments.length; ++i, c += 6) {
this[this.length] = {
model: arguments[i],
speed: cpuValues[c],
times: {
user: cpuValues[c + 1],
nice: cpuValues[c + 2],
sys: cpuValues[c + 3],
idle: cpuValues[c + 4],
irq: cpuValues[c + 5]
}
};
}
}
exports.cpus = function cpus() {
return getCPUs(addCPUInfo, cpuValues, []);
};
Object.defineProperty(exports, 'constants', { Object.defineProperty(exports, 'constants', {
configurable: false, configurable: false,
enumerable: true, enumerable: true,

58
src/node_os.cc

@ -32,6 +32,7 @@ using v8::ArrayBuffer;
using v8::Boolean; using v8::Boolean;
using v8::Context; using v8::Context;
using v8::Float64Array; using v8::Float64Array;
using v8::Function;
using v8::FunctionCallbackInfo; using v8::FunctionCallbackInfo;
using v8::Integer; using v8::Integer;
using v8::Local; using v8::Local;
@ -122,36 +123,47 @@ static void GetOSRelease(const FunctionCallbackInfo<Value>& args) {
static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) { static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
uv_cpu_info_t* cpu_infos; uv_cpu_info_t* cpu_infos;
int count, i; int count, i, field_idx;
int err = uv_cpu_info(&cpu_infos, &count); int err = uv_cpu_info(&cpu_infos, &count);
if (err) if (err)
return; return;
Local<Array> cpus = Array::New(env->isolate()); CHECK(args[0]->IsFunction());
for (i = 0; i < count; i++) { Local<Function> addfn = args[0].As<Function>();
CHECK(args[1]->IsFloat64Array());
Local<Float64Array> array = args[1].As<Float64Array>();
CHECK_EQ(array->Length(), 6 * NODE_PUSH_VAL_TO_ARRAY_MAX);
Local<ArrayBuffer> ab = array->Buffer();
double* fields = static_cast<double*>(ab->GetContents().Data());
CHECK(args[2]->IsArray());
Local<Array> cpus = args[2].As<Array>();
Local<Value> model_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
int model_idx = 0;
for (i = 0, field_idx = 0; i < count; i++) {
uv_cpu_info_t* ci = cpu_infos + i; uv_cpu_info_t* ci = cpu_infos + i;
Local<Object> times_info = Object::New(env->isolate()); fields[field_idx++] = ci->speed;
times_info->Set(env->user_string(), fields[field_idx++] = ci->cpu_times.user;
Number::New(env->isolate(), ci->cpu_times.user)); fields[field_idx++] = ci->cpu_times.nice;
times_info->Set(env->nice_string(), fields[field_idx++] = ci->cpu_times.sys;
Number::New(env->isolate(), ci->cpu_times.nice)); fields[field_idx++] = ci->cpu_times.idle;
times_info->Set(env->sys_string(), fields[field_idx++] = ci->cpu_times.irq;
Number::New(env->isolate(), ci->cpu_times.sys)); model_argv[model_idx++] = OneByteString(env->isolate(), ci->model);
times_info->Set(env->idle_string(),
Number::New(env->isolate(), ci->cpu_times.idle)); if (model_idx >= NODE_PUSH_VAL_TO_ARRAY_MAX) {
times_info->Set(env->irq_string(), addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked();
Number::New(env->isolate(), ci->cpu_times.irq)); model_idx = 0;
field_idx = 0;
Local<Object> cpu_info = Object::New(env->isolate()); }
cpu_info->Set(env->model_string(), }
OneByteString(env->isolate(), ci->model));
cpu_info->Set(env->speed_string(), if (model_idx > 0) {
Number::New(env->isolate(), ci->speed)); addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked();
cpu_info->Set(env->times_string(), times_info);
(*cpus)->Set(i, cpu_info);
} }
uv_free_cpu_info(cpu_infos, count); uv_free_cpu_info(cpu_infos, count);

6
src/node_util.cc

@ -141,6 +141,12 @@ void Initialize(Local<Object> target,
} }
#undef V #undef V
target->DefineOwnProperty(
env->context(),
OneByteString(env->isolate(), "pushValToArrayMax"),
Integer::NewFromUnsigned(env->isolate(), NODE_PUSH_VAL_TO_ARRAY_MAX),
v8::ReadOnly).FromJust();
env->SetMethod(target, "getHiddenValue", GetHiddenValue); env->SetMethod(target, "getHiddenValue", GetHiddenValue);
env->SetMethod(target, "setHiddenValue", SetHiddenValue); env->SetMethod(target, "setHiddenValue", SetHiddenValue);
env->SetMethod(target, "getProxyDetails", GetProxyDetails); env->SetMethod(target, "getProxyDetails", GetProxyDetails);

Loading…
Cancel
Save