diff --git a/benchmark/os/networkInterfaces.js b/benchmark/os/networkInterfaces.js new file mode 100644 index 00000000000000..3fa6073ae5c69e --- /dev/null +++ b/benchmark/os/networkInterfaces.js @@ -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); +} diff --git a/lib/os.js b/lib/os.js index 149289607d4952..cc86010f7d0ffb 100644 --- a/lib/os.js +++ b/lib/os.js @@ -143,18 +143,13 @@ endianness[Symbol.toPrimitive] = () => kEndianness; // Returns the number of ones in the binary representation of the decimal // number. function countBinaryOnes(n) { - let count = 0; - // Remove one "1" bit from n until n is the power of 2. This iterates k times - // while k is the number of "1" in the binary representation. - // For more check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators - while (n !== 0) { - n = n & (n - 1); - count++; - } - return count; + // Count the number of bits set in parallel, which is faster than looping + n = n - ((n >>> 1) & 0x55555555); + n = (n & 0x33333333) + ((n >>> 2) & 0x33333333); + return ((n + (n >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24; } -function getCIDR({ address, netmask, family }) { +function getCIDR(address, netmask, family) { let ones = 0; let split = '.'; let range = 10; @@ -190,17 +185,33 @@ function getCIDR({ address, netmask, family }) { } function networkInterfaces() { - const interfaceAddresses = getInterfaceAddresses(); + const data = getInterfaceAddresses(); + const result = {}; - const keys = Object.keys(interfaceAddresses); - for (var i = 0; i < keys.length; i++) { - const arr = interfaceAddresses[keys[i]]; - for (var j = 0; j < arr.length; j++) { - arr[j].cidr = getCIDR(arr[j]); - } + if (data === undefined) + return result; + for (var i = 0; i < data.length; i += 7) { + const name = data[i]; + 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) { diff --git a/src/node_os.cc b/src/node_os.cc index 6ecfb7fe9f8f44..505f42daf67fe4 100644 --- a/src/node_os.cc +++ b/src/node_os.cc @@ -213,28 +213,28 @@ static void GetLoadAvg(const FunctionCallbackInfo& args) { static void GetInterfaceAddresses(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); uv_interface_address_t* interfaces; int count, i; char ip[INET6_ADDRSTRLEN]; char netmask[INET6_ADDRSTRLEN]; std::array mac; - Local ret, o; Local name, family; - Local ifarr; int err = uv_interface_addresses(&interfaces, &count); - ret = Object::New(env->isolate()); + if (err == UV_ENOSYS) + return args.GetReturnValue().SetUndefined(); - if (err == UV_ENOSYS) { - return args.GetReturnValue().Set(ret); - } else if (err) { + if (err) { CHECK_GE(args.Length(), 1); env->CollectUVExceptionInfo(args[args.Length() - 1], errno, "uv_interface_addresses"); return args.GetReturnValue().SetUndefined(); } + Local no_scope_id = Integer::New(isolate, -1); + std::vector> result(count * 7); for (i = 0; i < count; i++) { const char* const raw_name = interfaces[i].name; @@ -243,17 +243,9 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo& args) { // 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 // 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(); - if (ret->Has(env->context(), name).FromJust()) { - ifarr = Local::Cast(ret->Get(env->context(), - name).ToLocalChecked()); - } else { - ifarr = Array::New(env->isolate()); - ret->Set(env->context(), name, ifarr).FromJust(); - } - snprintf(mac.data(), mac.size(), "%02x:%02x:%02x:%02x:%02x:%02x", @@ -277,34 +269,23 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo& args) { family = env->unknown_string(); } - o = Object::New(env->isolate()); - o->Set(env->context(), - env->address_string(), - OneByteString(env->isolate(), ip)).FromJust(); - o->Set(env->context(), - env->netmask_string(), - OneByteString(env->isolate(), netmask)).FromJust(); - o->Set(env->context(), - env->family_string(), family).FromJust(); - o->Set(env->context(), - env->mac_string(), - FIXED_ONE_BYTE_STRING(env->isolate(), mac)).FromJust(); - + result[i * 7] = name; + result[i * 7 + 1] = OneByteString(isolate, ip); + result[i * 7 + 2] = OneByteString(isolate, netmask); + result[i * 7 + 3] = family; + result[i * 7 + 4] = FIXED_ONE_BYTE_STRING(isolate, mac); + result[i * 7 + 5] = + interfaces[i].is_internal ? True(isolate) : False(isolate); if (interfaces[i].address.address4.sin_family == AF_INET6) { uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id; - o->Set(env->context(), env->scopeid_string(), - Integer::NewFromUnsigned(env->isolate(), scopeid)).FromJust(); + result[i * 7 + 6] = Integer::NewFromUnsigned(isolate, scopeid); + } 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); - args.GetReturnValue().Set(ret); + args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size())); }