Skip to content

Commit 6be73fe

Browse files
committed
crypto,tls: perf improvements for crypto and tls getCiphers
Improve performance of crypto.getCiphers, getHashes, getCurves and tls.getCiphers by consolidating filterDuplicates logic, adding caching of output, and streamlining filterDuplicates implementation. Benchmarks: crypto.getCiphers n=1 v6.2.1 = 2559.3, new = 15890 ...... -83.89% crypto.getCiphers n=5000 v6.2.1 = 3516.3, new = 24203000 ... -99.99% tls.getCiphers n=1 v6.2.1 = 3405.3, new = 14877 ...... -77.11% tls.getCiphers n=5000 v6.2.1 = 6074.4, new = 24202000 ... -99.97% PR-URL: #7225 Reviewed-By: Fedor Indutny <[email protected]> Reviewed-By: Brian White <[email protected]>
1 parent 58a241d commit 6be73fe

File tree

4 files changed

+65
-38
lines changed

4 files changed

+65
-38
lines changed

benchmark/crypto/get-ciphers.js

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

lib/crypto.js

+9-27
Original file line numberDiff line numberDiff line change
@@ -632,41 +632,23 @@ exports.randomBytes = exports.pseudoRandomBytes = randomBytes;
632632

633633
exports.rng = exports.prng = randomBytes;
634634

635-
exports.getCiphers = function() {
636-
return filterDuplicates(getCiphers());
637-
};
638-
639-
640-
exports.getHashes = function() {
641-
return filterDuplicates(getHashes());
642-
};
635+
exports.getCiphers = internalUtil.cachedResult(() => {
636+
return internalUtil.filterDuplicateStrings(getCiphers());
637+
});
643638

639+
exports.getHashes = internalUtil.cachedResult(() => {
640+
return internalUtil.filterDuplicateStrings(getHashes());
641+
});
644642

645-
exports.getCurves = function() {
646-
return filterDuplicates(getCurves());
647-
};
643+
exports.getCurves = internalUtil.cachedResult(() => {
644+
return internalUtil.filterDuplicateStrings(getCurves());
645+
});
648646

649647
Object.defineProperty(exports, 'fips', {
650648
get: getFipsCrypto,
651649
set: setFipsCrypto
652650
});
653651

654-
function filterDuplicates(names) {
655-
// Drop all-caps names in favor of their lowercase aliases,
656-
// for example, 'sha1' instead of 'SHA1'.
657-
var ctx = {};
658-
names.forEach(function(name) {
659-
var key = name;
660-
if (/^[0-9A-Z\-]+$/.test(key)) key = key.toLowerCase();
661-
if (!ctx.hasOwnProperty(key) || ctx[key] < name)
662-
ctx[key] = name;
663-
});
664-
665-
return Object.getOwnPropertyNames(ctx).map(function(key) {
666-
return ctx[key];
667-
}).sort();
668-
}
669-
670652
// Legacy API
671653
Object.defineProperty(exports, 'createCredentials', {
672654
configurable: true,

lib/internal/util.js

+31
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,34 @@ exports.normalizeEncoding = function normalizeEncoding(enc) {
121121
}
122122
}
123123
};
124+
125+
// Filters duplicate strings. Used to support functions in crypto and tls
126+
// modules. Implemented specifically to maintain existing behaviors in each.
127+
exports.filterDuplicateStrings = function filterDuplicateStrings(items, low) {
128+
if (!Array.isArray(items))
129+
return [];
130+
const len = items.length;
131+
if (len <= 1)
132+
return items;
133+
const map = new Map();
134+
for (var i = 0; i < len; i++) {
135+
const item = items[i];
136+
const key = item.toLowerCase();
137+
if (low) {
138+
map.set(key, key);
139+
} else {
140+
if (!map.has(key) || map.get(key) <= item)
141+
map.set(key, item);
142+
}
143+
}
144+
return Array.from(map.values()).sort();
145+
};
146+
147+
exports.cachedResult = function cachedResult(fn) {
148+
var result;
149+
return () => {
150+
if (result === undefined)
151+
result = fn();
152+
return result;
153+
};
154+
};

lib/tls.js

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

3-
require('internal/util').assertCrypto(exports);
3+
const internalUtil = require('internal/util');
4+
internalUtil.assertCrypto(exports);
45

56
const net = require('net');
67
const url = require('url');
@@ -21,16 +22,9 @@ exports.DEFAULT_CIPHERS =
2122

2223
exports.DEFAULT_ECDH_CURVE = 'prime256v1';
2324

24-
exports.getCiphers = function() {
25-
const names = binding.getSSLCiphers();
26-
// Drop all-caps names in favor of their lowercase aliases,
27-
var ctx = {};
28-
names.forEach(function(name) {
29-
if (/^[0-9A-Z\-]+$/.test(name)) name = name.toLowerCase();
30-
ctx[name] = true;
31-
});
32-
return Object.getOwnPropertyNames(ctx).sort();
33-
};
25+
exports.getCiphers = internalUtil.cachedResult(() => {
26+
return internalUtil.filterDuplicateStrings(binding.getSSLCiphers(), true);
27+
});
3428

3529
// Convert protocols array into valid OpenSSL protocols list
3630
// ("\x06spdy/2\x08http/1.1\x08http/1.0")

0 commit comments

Comments
 (0)