Skip to content

Commit e2133f3

Browse files
mscdexaddaleax
authored andcommittedMar 5, 2017
os: improve cpus() performance
PR-URL: #11564 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Jackson Tian <[email protected]>
1 parent ac3deb1 commit e2133f3

File tree

4 files changed

+80
-24
lines changed

4 files changed

+80
-24
lines changed
 

‎benchmark/os/cpus.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const cpus = require('os').cpus;
5+
6+
const bench = common.createBenchmark(main, {
7+
n: [3e4]
8+
});
9+
10+
function main(conf) {
11+
const n = +conf.n;
12+
13+
bench.start();
14+
for (var i = 0; i < n; ++i)
15+
cpus();
16+
bench.end(n);
17+
}

‎lib/os.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
'use strict';
22

33
const binding = process.binding('os');
4+
const getCPUs = binding.getCPUs;
45
const getLoadAvg = binding.getLoadAvg;
6+
const pushValToArrayMax = process.binding('util').pushValToArrayMax;
57
const constants = process.binding('constants').os;
68
const internalUtil = require('internal/util');
79
const isWindows = process.platform === 'win32';
@@ -10,7 +12,6 @@ exports.hostname = binding.getHostname;
1012
exports.uptime = binding.getUptime;
1113
exports.freemem = binding.getFreeMem;
1214
exports.totalmem = binding.getTotalMem;
13-
exports.cpus = binding.getCPUs;
1415
exports.type = binding.getOSType;
1516
exports.release = binding.getOSRelease;
1617
exports.networkInterfaces = binding.getInterfaceAddresses;
@@ -23,6 +24,26 @@ exports.loadavg = function loadavg() {
2324
return [avgValues[0], avgValues[1], avgValues[2]];
2425
};
2526

27+
const cpuValues = new Float64Array(6 * pushValToArrayMax);
28+
function addCPUInfo() {
29+
for (var i = 0, c = 0; i < arguments.length; ++i, c += 6) {
30+
this[this.length] = {
31+
model: arguments[i],
32+
speed: cpuValues[c],
33+
times: {
34+
user: cpuValues[c + 1],
35+
nice: cpuValues[c + 2],
36+
sys: cpuValues[c + 3],
37+
idle: cpuValues[c + 4],
38+
irq: cpuValues[c + 5]
39+
}
40+
};
41+
}
42+
}
43+
exports.cpus = function cpus() {
44+
return getCPUs(addCPUInfo, cpuValues, []);
45+
};
46+
2647
Object.defineProperty(exports, 'constants', {
2748
configurable: false,
2849
enumerable: true,

‎src/node_os.cc

+35-23
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ using v8::ArrayBuffer;
3232
using v8::Boolean;
3333
using v8::Context;
3434
using v8::Float64Array;
35+
using v8::Function;
3536
using v8::FunctionCallbackInfo;
3637
using v8::Integer;
3738
using v8::Local;
@@ -122,36 +123,47 @@ static void GetOSRelease(const FunctionCallbackInfo<Value>& args) {
122123
static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) {
123124
Environment* env = Environment::GetCurrent(args);
124125
uv_cpu_info_t* cpu_infos;
125-
int count, i;
126+
int count, i, field_idx;
126127

127128
int err = uv_cpu_info(&cpu_infos, &count);
128129
if (err)
129130
return;
130131

131-
Local<Array> cpus = Array::New(env->isolate());
132-
for (i = 0; i < count; i++) {
132+
CHECK(args[0]->IsFunction());
133+
Local<Function> addfn = args[0].As<Function>();
134+
135+
CHECK(args[1]->IsFloat64Array());
136+
Local<Float64Array> array = args[1].As<Float64Array>();
137+
CHECK_EQ(array->Length(), 6 * NODE_PUSH_VAL_TO_ARRAY_MAX);
138+
Local<ArrayBuffer> ab = array->Buffer();
139+
double* fields = static_cast<double*>(ab->GetContents().Data());
140+
141+
CHECK(args[2]->IsArray());
142+
Local<Array> cpus = args[2].As<Array>();
143+
144+
Local<Value> model_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
145+
int model_idx = 0;
146+
147+
for (i = 0, field_idx = 0; i < count; i++) {
133148
uv_cpu_info_t* ci = cpu_infos + i;
134149

135-
Local<Object> times_info = Object::New(env->isolate());
136-
times_info->Set(env->user_string(),
137-
Number::New(env->isolate(), ci->cpu_times.user));
138-
times_info->Set(env->nice_string(),
139-
Number::New(env->isolate(), ci->cpu_times.nice));
140-
times_info->Set(env->sys_string(),
141-
Number::New(env->isolate(), ci->cpu_times.sys));
142-
times_info->Set(env->idle_string(),
143-
Number::New(env->isolate(), ci->cpu_times.idle));
144-
times_info->Set(env->irq_string(),
145-
Number::New(env->isolate(), ci->cpu_times.irq));
146-
147-
Local<Object> cpu_info = Object::New(env->isolate());
148-
cpu_info->Set(env->model_string(),
149-
OneByteString(env->isolate(), ci->model));
150-
cpu_info->Set(env->speed_string(),
151-
Number::New(env->isolate(), ci->speed));
152-
cpu_info->Set(env->times_string(), times_info);
153-
154-
(*cpus)->Set(i, cpu_info);
150+
fields[field_idx++] = ci->speed;
151+
fields[field_idx++] = ci->cpu_times.user;
152+
fields[field_idx++] = ci->cpu_times.nice;
153+
fields[field_idx++] = ci->cpu_times.sys;
154+
fields[field_idx++] = ci->cpu_times.idle;
155+
fields[field_idx++] = ci->cpu_times.irq;
156+
model_argv[model_idx++] = OneByteString(env->isolate(), ci->model);
157+
158+
if (model_idx >= NODE_PUSH_VAL_TO_ARRAY_MAX) {
159+
addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked();
160+
model_idx = 0;
161+
field_idx = 0;
162+
}
163+
}
164+
165+
if (model_idx > 0) {
166+
addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked();
155167
}
156168

157169
uv_free_cpu_info(cpu_infos, count);

‎src/node_util.cc

+6
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ void Initialize(Local<Object> target,
141141
}
142142
#undef V
143143

144+
target->DefineOwnProperty(
145+
env->context(),
146+
OneByteString(env->isolate(), "pushValToArrayMax"),
147+
Integer::NewFromUnsigned(env->isolate(), NODE_PUSH_VAL_TO_ARRAY_MAX),
148+
v8::ReadOnly).FromJust();
149+
144150
env->SetMethod(target, "getHiddenValue", GetHiddenValue);
145151
env->SetMethod(target, "setHiddenValue", SetHiddenValue);
146152
env->SetMethod(target, "getProxyDetails", GetProxyDetails);

0 commit comments

Comments
 (0)
Please sign in to comment.