From e2133f3e572d62a97a3ea80cf181e32775e60499 Mon Sep 17 00:00:00 2001 From: Brian White Date: Sat, 25 Feb 2017 23:40:39 -0500 Subject: [PATCH] os: improve cpus() performance PR-URL: https://github.com/nodejs/node/pull/11564 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Jackson Tian --- benchmark/os/cpus.js | 17 +++++++++++++ lib/os.js | 23 +++++++++++++++++- src/node_os.cc | 58 ++++++++++++++++++++++++++------------------ src/node_util.cc | 6 +++++ 4 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 benchmark/os/cpus.js diff --git a/benchmark/os/cpus.js b/benchmark/os/cpus.js new file mode 100644 index 00000000000000..2a8535113c207a --- /dev/null +++ b/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); +} diff --git a/lib/os.js b/lib/os.js index 6d8ebd1ca55659..b2b960ea63d029 100644 --- a/lib/os.js +++ b/lib/os.js @@ -1,7 +1,9 @@ 'use strict'; const binding = process.binding('os'); +const getCPUs = binding.getCPUs; const getLoadAvg = binding.getLoadAvg; +const pushValToArrayMax = process.binding('util').pushValToArrayMax; const constants = process.binding('constants').os; const internalUtil = require('internal/util'); const isWindows = process.platform === 'win32'; @@ -10,7 +12,6 @@ exports.hostname = binding.getHostname; exports.uptime = binding.getUptime; exports.freemem = binding.getFreeMem; exports.totalmem = binding.getTotalMem; -exports.cpus = binding.getCPUs; exports.type = binding.getOSType; exports.release = binding.getOSRelease; exports.networkInterfaces = binding.getInterfaceAddresses; @@ -23,6 +24,26 @@ exports.loadavg = function loadavg() { 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', { configurable: false, enumerable: true, diff --git a/src/node_os.cc b/src/node_os.cc index 211ac3d01dd8b2..c3f3ed75ab7d5d 100644 --- a/src/node_os.cc +++ b/src/node_os.cc @@ -32,6 +32,7 @@ using v8::ArrayBuffer; using v8::Boolean; using v8::Context; using v8::Float64Array; +using v8::Function; using v8::FunctionCallbackInfo; using v8::Integer; using v8::Local; @@ -122,36 +123,47 @@ static void GetOSRelease(const FunctionCallbackInfo& args) { static void GetCPUInfo(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); uv_cpu_info_t* cpu_infos; - int count, i; + int count, i, field_idx; int err = uv_cpu_info(&cpu_infos, &count); if (err) return; - Local cpus = Array::New(env->isolate()); - for (i = 0; i < count; i++) { + CHECK(args[0]->IsFunction()); + Local addfn = args[0].As(); + + CHECK(args[1]->IsFloat64Array()); + Local array = args[1].As(); + CHECK_EQ(array->Length(), 6 * NODE_PUSH_VAL_TO_ARRAY_MAX); + Local ab = array->Buffer(); + double* fields = static_cast(ab->GetContents().Data()); + + CHECK(args[2]->IsArray()); + Local cpus = args[2].As(); + + Local 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; - Local times_info = Object::New(env->isolate()); - times_info->Set(env->user_string(), - Number::New(env->isolate(), ci->cpu_times.user)); - times_info->Set(env->nice_string(), - Number::New(env->isolate(), ci->cpu_times.nice)); - times_info->Set(env->sys_string(), - Number::New(env->isolate(), ci->cpu_times.sys)); - times_info->Set(env->idle_string(), - Number::New(env->isolate(), ci->cpu_times.idle)); - times_info->Set(env->irq_string(), - Number::New(env->isolate(), ci->cpu_times.irq)); - - Local cpu_info = Object::New(env->isolate()); - cpu_info->Set(env->model_string(), - OneByteString(env->isolate(), ci->model)); - cpu_info->Set(env->speed_string(), - Number::New(env->isolate(), ci->speed)); - cpu_info->Set(env->times_string(), times_info); - - (*cpus)->Set(i, cpu_info); + fields[field_idx++] = ci->speed; + fields[field_idx++] = ci->cpu_times.user; + fields[field_idx++] = ci->cpu_times.nice; + fields[field_idx++] = ci->cpu_times.sys; + fields[field_idx++] = ci->cpu_times.idle; + fields[field_idx++] = ci->cpu_times.irq; + model_argv[model_idx++] = OneByteString(env->isolate(), ci->model); + + if (model_idx >= NODE_PUSH_VAL_TO_ARRAY_MAX) { + addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked(); + model_idx = 0; + field_idx = 0; + } + } + + if (model_idx > 0) { + addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked(); } uv_free_cpu_info(cpu_infos, count); diff --git a/src/node_util.cc b/src/node_util.cc index a1387353e3d9a5..8279a787d7d1ac 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -141,6 +141,12 @@ void Initialize(Local target, } #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, "setHiddenValue", SetHiddenValue); env->SetMethod(target, "getProxyDetails", GetProxyDetails);