Skip to content

Commit 840ec23

Browse files
mscdexaddaleax
authored andcommitted
os: improve networkInterfaces() performance
PR-URL: #25410 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
1 parent 29b89ba commit 840ec23

File tree

3 files changed

+62
-55
lines changed

3 files changed

+62
-55
lines changed

benchmark/os/networkInterfaces.js

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

lib/os.js

+29-18
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,13 @@ endianness[Symbol.toPrimitive] = () => kEndianness;
146146
// Returns the number of ones in the binary representation of the decimal
147147
// number.
148148
function countBinaryOnes(n) {
149-
let count = 0;
150-
// Remove one "1" bit from n until n is the power of 2. This iterates k times
151-
// while k is the number of "1" in the binary representation.
152-
// For more check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
153-
while (n !== 0) {
154-
n = n & (n - 1);
155-
count++;
156-
}
157-
return count;
149+
// Count the number of bits set in parallel, which is faster than looping
150+
n = n - ((n >>> 1) & 0x55555555);
151+
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
152+
return ((n + (n >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
158153
}
159154

160-
function getCIDR({ address, netmask, family }) {
155+
function getCIDR(address, netmask, family) {
161156
let ones = 0;
162157
let split = '.';
163158
let range = 10;
@@ -193,17 +188,33 @@ function getCIDR({ address, netmask, family }) {
193188
}
194189

195190
function networkInterfaces() {
196-
const interfaceAddresses = getInterfaceAddresses();
191+
const data = getInterfaceAddresses();
192+
const result = {};
197193

198-
const keys = Object.keys(interfaceAddresses);
199-
for (var i = 0; i < keys.length; i++) {
200-
const arr = interfaceAddresses[keys[i]];
201-
for (var j = 0; j < arr.length; j++) {
202-
arr[j].cidr = getCIDR(arr[j]);
203-
}
194+
if (data === undefined)
195+
return result;
196+
for (var i = 0; i < data.length; i += 7) {
197+
const name = data[i];
198+
const entry = {
199+
address: data[i + 1],
200+
netmask: data[i + 2],
201+
family: data[i + 3],
202+
mac: data[i + 4],
203+
internal: data[i + 5],
204+
cidr: getCIDR(data[i + 1], data[i + 2], data[i + 3])
205+
};
206+
const scopeid = data[i + 6];
207+
if (scopeid !== -1)
208+
entry.scopeid = scopeid;
209+
210+
const existing = result[name];
211+
if (existing !== undefined)
212+
existing.push(entry);
213+
else
214+
result[name] = [entry];
204215
}
205216

206-
return interfaceAddresses;
217+
return result;
207218
}
208219

209220
function setPriority(pid, priority) {

src/node_os.cc

+18-37
Original file line numberDiff line numberDiff line change
@@ -213,28 +213,28 @@ static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) {
213213

214214
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
215215
Environment* env = Environment::GetCurrent(args);
216+
Isolate* isolate = env->isolate();
216217
uv_interface_address_t* interfaces;
217218
int count, i;
218219
char ip[INET6_ADDRSTRLEN];
219220
char netmask[INET6_ADDRSTRLEN];
220221
std::array<char, 18> mac;
221-
Local<Object> ret, o;
222222
Local<String> name, family;
223-
Local<Array> ifarr;
224223

225224
int err = uv_interface_addresses(&interfaces, &count);
226225

227-
ret = Object::New(env->isolate());
226+
if (err == UV_ENOSYS)
227+
return args.GetReturnValue().SetUndefined();
228228

229-
if (err == UV_ENOSYS) {
230-
return args.GetReturnValue().Set(ret);
231-
} else if (err) {
229+
if (err) {
232230
CHECK_GE(args.Length(), 1);
233231
env->CollectUVExceptionInfo(args[args.Length() - 1], errno,
234232
"uv_interface_addresses");
235233
return args.GetReturnValue().SetUndefined();
236234
}
237235

236+
Local<Value> no_scope_id = Integer::New(isolate, -1);
237+
std::vector<Local<Value>> result(count * 7);
238238
for (i = 0; i < count; i++) {
239239
const char* const raw_name = interfaces[i].name;
240240

@@ -243,17 +243,9 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
243243
// to assume UTF8 as the default as well. It’s what people will expect if
244244
// they name the interface from any input that uses UTF-8, which should be
245245
// the most frequent case by far these days.)
246-
name = String::NewFromUtf8(env->isolate(), raw_name,
246+
name = String::NewFromUtf8(isolate, raw_name,
247247
v8::NewStringType::kNormal).ToLocalChecked();
248248

249-
if (ret->Has(env->context(), name).FromJust()) {
250-
ifarr = Local<Array>::Cast(ret->Get(env->context(),
251-
name).ToLocalChecked());
252-
} else {
253-
ifarr = Array::New(env->isolate());
254-
ret->Set(env->context(), name, ifarr).FromJust();
255-
}
256-
257249
snprintf(mac.data(),
258250
mac.size(),
259251
"%02x:%02x:%02x:%02x:%02x:%02x",
@@ -277,34 +269,23 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
277269
family = env->unknown_string();
278270
}
279271

280-
o = Object::New(env->isolate());
281-
o->Set(env->context(),
282-
env->address_string(),
283-
OneByteString(env->isolate(), ip)).FromJust();
284-
o->Set(env->context(),
285-
env->netmask_string(),
286-
OneByteString(env->isolate(), netmask)).FromJust();
287-
o->Set(env->context(),
288-
env->family_string(), family).FromJust();
289-
o->Set(env->context(),
290-
env->mac_string(),
291-
FIXED_ONE_BYTE_STRING(env->isolate(), mac)).FromJust();
292-
272+
result[i * 7] = name;
273+
result[i * 7 + 1] = OneByteString(isolate, ip);
274+
result[i * 7 + 2] = OneByteString(isolate, netmask);
275+
result[i * 7 + 3] = family;
276+
result[i * 7 + 4] = FIXED_ONE_BYTE_STRING(isolate, mac);
277+
result[i * 7 + 5] =
278+
interfaces[i].is_internal ? True(isolate) : False(isolate);
293279
if (interfaces[i].address.address4.sin_family == AF_INET6) {
294280
uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
295-
o->Set(env->context(), env->scopeid_string(),
296-
Integer::NewFromUnsigned(env->isolate(), scopeid)).FromJust();
281+
result[i * 7 + 6] = Integer::NewFromUnsigned(isolate, scopeid);
282+
} else {
283+
result[i * 7 + 6] = no_scope_id;
297284
}
298-
299-
const bool internal = interfaces[i].is_internal;
300-
o->Set(env->context(), env->internal_string(),
301-
internal ? True(env->isolate()) : False(env->isolate())).FromJust();
302-
303-
ifarr->Set(env->context(), ifarr->Length(), o).FromJust();
304285
}
305286

306287
uv_free_interface_addresses(interfaces, count);
307-
args.GetReturnValue().Set(ret);
288+
args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
308289
}
309290

310291

0 commit comments

Comments
 (0)