os: improve networkInterfaces() performance
PR-URL: https://github.com/nodejs/node/pull/25410 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
This commit is contained in:
parent
641b0135cf
commit
5021b259ed
15
benchmark/os/networkInterfaces.js
Normal file
15
benchmark/os/networkInterfaces.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common.js');
|
||||||
|
const networkInterfaces = require('os').networkInterfaces;
|
||||||
|
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
n: [1e4]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main({ n }) {
|
||||||
|
bench.start();
|
||||||
|
for (var i = 0; i < n; ++i)
|
||||||
|
networkInterfaces();
|
||||||
|
bench.end(n);
|
||||||
|
}
|
47
lib/os.js
47
lib/os.js
@ -143,18 +143,13 @@ endianness[Symbol.toPrimitive] = () => kEndianness;
|
|||||||
// Returns the number of ones in the binary representation of the decimal
|
// Returns the number of ones in the binary representation of the decimal
|
||||||
// number.
|
// number.
|
||||||
function countBinaryOnes(n) {
|
function countBinaryOnes(n) {
|
||||||
let count = 0;
|
// Count the number of bits set in parallel, which is faster than looping
|
||||||
// Remove one "1" bit from n until n is the power of 2. This iterates k times
|
n = n - ((n >>> 1) & 0x55555555);
|
||||||
// while k is the number of "1" in the binary representation.
|
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
|
||||||
// For more check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
|
return ((n + (n >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
|
||||||
while (n !== 0) {
|
|
||||||
n = n & (n - 1);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCIDR({ address, netmask, family }) {
|
function getCIDR(address, netmask, family) {
|
||||||
let ones = 0;
|
let ones = 0;
|
||||||
let split = '.';
|
let split = '.';
|
||||||
let range = 10;
|
let range = 10;
|
||||||
@ -190,17 +185,33 @@ function getCIDR({ address, netmask, family }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function networkInterfaces() {
|
function networkInterfaces() {
|
||||||
const interfaceAddresses = getInterfaceAddresses();
|
const data = getInterfaceAddresses();
|
||||||
|
const result = {};
|
||||||
|
|
||||||
const keys = Object.keys(interfaceAddresses);
|
if (data === undefined)
|
||||||
for (var i = 0; i < keys.length; i++) {
|
return result;
|
||||||
const arr = interfaceAddresses[keys[i]];
|
for (var i = 0; i < data.length; i += 7) {
|
||||||
for (var j = 0; j < arr.length; j++) {
|
const name = data[i];
|
||||||
arr[j].cidr = getCIDR(arr[j]);
|
const entry = {
|
||||||
}
|
address: data[i + 1],
|
||||||
|
netmask: data[i + 2],
|
||||||
|
family: data[i + 3],
|
||||||
|
mac: data[i + 4],
|
||||||
|
internal: data[i + 5],
|
||||||
|
cidr: getCIDR(data[i + 1], data[i + 2], data[i + 3])
|
||||||
|
};
|
||||||
|
const scopeid = data[i + 6];
|
||||||
|
if (scopeid !== -1)
|
||||||
|
entry.scopeid = scopeid;
|
||||||
|
|
||||||
|
const existing = result[name];
|
||||||
|
if (existing !== undefined)
|
||||||
|
existing.push(entry);
|
||||||
|
else
|
||||||
|
result[name] = [entry];
|
||||||
}
|
}
|
||||||
|
|
||||||
return interfaceAddresses;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPriority(pid, priority) {
|
function setPriority(pid, priority) {
|
||||||
|
@ -213,28 +213,28 @@ static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
|
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
Isolate* isolate = env->isolate();
|
||||||
uv_interface_address_t* interfaces;
|
uv_interface_address_t* interfaces;
|
||||||
int count, i;
|
int count, i;
|
||||||
char ip[INET6_ADDRSTRLEN];
|
char ip[INET6_ADDRSTRLEN];
|
||||||
char netmask[INET6_ADDRSTRLEN];
|
char netmask[INET6_ADDRSTRLEN];
|
||||||
std::array<char, 18> mac;
|
std::array<char, 18> mac;
|
||||||
Local<Object> ret, o;
|
|
||||||
Local<String> name, family;
|
Local<String> name, family;
|
||||||
Local<Array> ifarr;
|
|
||||||
|
|
||||||
int err = uv_interface_addresses(&interfaces, &count);
|
int err = uv_interface_addresses(&interfaces, &count);
|
||||||
|
|
||||||
ret = Object::New(env->isolate());
|
if (err == UV_ENOSYS)
|
||||||
|
return args.GetReturnValue().SetUndefined();
|
||||||
|
|
||||||
if (err == UV_ENOSYS) {
|
if (err) {
|
||||||
return args.GetReturnValue().Set(ret);
|
|
||||||
} else if (err) {
|
|
||||||
CHECK_GE(args.Length(), 1);
|
CHECK_GE(args.Length(), 1);
|
||||||
env->CollectUVExceptionInfo(args[args.Length() - 1], errno,
|
env->CollectUVExceptionInfo(args[args.Length() - 1], errno,
|
||||||
"uv_interface_addresses");
|
"uv_interface_addresses");
|
||||||
return args.GetReturnValue().SetUndefined();
|
return args.GetReturnValue().SetUndefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Local<Value> no_scope_id = Integer::New(isolate, -1);
|
||||||
|
std::vector<Local<Value>> result(count * 7);
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
const char* const raw_name = interfaces[i].name;
|
const char* const raw_name = interfaces[i].name;
|
||||||
|
|
||||||
@ -243,17 +243,9 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// to assume UTF8 as the default as well. It’s what people will expect if
|
// to assume UTF8 as the default as well. It’s what people will expect if
|
||||||
// they name the interface from any input that uses UTF-8, which should be
|
// they name the interface from any input that uses UTF-8, which should be
|
||||||
// the most frequent case by far these days.)
|
// the most frequent case by far these days.)
|
||||||
name = String::NewFromUtf8(env->isolate(), raw_name,
|
name = String::NewFromUtf8(isolate, raw_name,
|
||||||
v8::NewStringType::kNormal).ToLocalChecked();
|
v8::NewStringType::kNormal).ToLocalChecked();
|
||||||
|
|
||||||
if (ret->Has(env->context(), name).FromJust()) {
|
|
||||||
ifarr = Local<Array>::Cast(ret->Get(env->context(),
|
|
||||||
name).ToLocalChecked());
|
|
||||||
} else {
|
|
||||||
ifarr = Array::New(env->isolate());
|
|
||||||
ret->Set(env->context(), name, ifarr).FromJust();
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(mac.data(),
|
snprintf(mac.data(),
|
||||||
mac.size(),
|
mac.size(),
|
||||||
"%02x:%02x:%02x:%02x:%02x:%02x",
|
"%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
@ -277,34 +269,23 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
|
|||||||
family = env->unknown_string();
|
family = env->unknown_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
o = Object::New(env->isolate());
|
result[i * 7] = name;
|
||||||
o->Set(env->context(),
|
result[i * 7 + 1] = OneByteString(isolate, ip);
|
||||||
env->address_string(),
|
result[i * 7 + 2] = OneByteString(isolate, netmask);
|
||||||
OneByteString(env->isolate(), ip)).FromJust();
|
result[i * 7 + 3] = family;
|
||||||
o->Set(env->context(),
|
result[i * 7 + 4] = FIXED_ONE_BYTE_STRING(isolate, mac);
|
||||||
env->netmask_string(),
|
result[i * 7 + 5] =
|
||||||
OneByteString(env->isolate(), netmask)).FromJust();
|
interfaces[i].is_internal ? True(isolate) : False(isolate);
|
||||||
o->Set(env->context(),
|
|
||||||
env->family_string(), family).FromJust();
|
|
||||||
o->Set(env->context(),
|
|
||||||
env->mac_string(),
|
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), mac)).FromJust();
|
|
||||||
|
|
||||||
if (interfaces[i].address.address4.sin_family == AF_INET6) {
|
if (interfaces[i].address.address4.sin_family == AF_INET6) {
|
||||||
uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
|
uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
|
||||||
o->Set(env->context(), env->scopeid_string(),
|
result[i * 7 + 6] = Integer::NewFromUnsigned(isolate, scopeid);
|
||||||
Integer::NewFromUnsigned(env->isolate(), scopeid)).FromJust();
|
} else {
|
||||||
|
result[i * 7 + 6] = no_scope_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool internal = interfaces[i].is_internal;
|
|
||||||
o->Set(env->context(), env->internal_string(),
|
|
||||||
internal ? True(env->isolate()) : False(env->isolate())).FromJust();
|
|
||||||
|
|
||||||
ifarr->Set(env->context(), ifarr->Length(), o).FromJust();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uv_free_interface_addresses(interfaces, count);
|
uv_free_interface_addresses(interfaces, count);
|
||||||
args.GetReturnValue().Set(ret);
|
args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user