Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 840ec23

Browse filesBrowse 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
Copy full SHA for 840ec23

File tree

Expand file treeCollapse file tree

3 files changed

+62
-55
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+62
-55
lines changed
Open diff view settings
Collapse file

‎benchmark/os/networkInterfaces.js‎

Copy file name to clipboard
+15Lines changed: 15 additions & 0 deletions
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+
}
Collapse file

‎lib/os.js‎

Copy file name to clipboardExpand all lines: lib/os.js
+29-18Lines changed: 29 additions & 18 deletions
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) {
Collapse file

‎src/node_os.cc‎

Copy file name to clipboardExpand all lines: src/node_os.cc
+18-37Lines changed: 18 additions & 37 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.