benchmark: refactor crypto oneshot

PR-URL: https://github.com/nodejs/node/pull/48267
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
Filip Skokan 2023-06-05 20:00:41 +01:00 committed by GitHub
parent 41f8abc6b5
commit 0e92bf1b66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 282 additions and 141 deletions

View File

@ -1,141 +0,0 @@
'use strict';
const common = require('../common.js');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/');
const keyFixtures = {
publicKey: fs.readFileSync(`${fixtures_keydir}/ec_p256_public.pem`)
.toString(),
privateKey: fs.readFileSync(`${fixtures_keydir}/ec_p256_private.pem`)
.toString(),
};
const data = crypto.randomBytes(256);
let pems;
let keyObjects;
function getKeyObject({ privateKey, publicKey }) {
return {
privateKey: crypto.createPrivateKey(privateKey),
publicKey: crypto.createPublicKey(publicKey),
};
}
const bench = common.createBenchmark(main, {
mode: ['sync', 'async-serial', 'async-parallel'],
keyFormat: ['pem', 'keyObject', 'pem.unique', 'keyObject.unique'],
n: [1e3],
});
function measureSync(n, privateKey, publicKey, keys) {
bench.start();
for (let i = 0; i < n; ++i) {
crypto.verify(
'sha256',
data,
{ key: publicKey || keys[i].publicKey, dsaEncoding: 'ieee-p1363' },
crypto.sign(
'sha256',
data,
{ key: privateKey || keys[i].privateKey, dsaEncoding: 'ieee-p1363' }));
}
bench.end(n);
}
function measureAsyncSerial(n, privateKey, publicKey, keys) {
let remaining = n;
function done() {
if (--remaining === 0)
bench.end(n);
else
one();
}
function one() {
crypto.sign(
'sha256',
data,
{
key: privateKey || keys[n - remaining].privateKey,
dsaEncoding: 'ieee-p1363',
},
(err, signature) => {
crypto.verify(
'sha256',
data,
{
key: publicKey || keys[n - remaining].publicKey,
dsaEncoding: 'ieee-p1363',
},
signature,
done);
});
}
bench.start();
one();
}
function measureAsyncParallel(n, privateKey, publicKey, keys) {
let remaining = n;
function done() {
if (--remaining === 0)
bench.end(n);
}
bench.start();
for (let i = 0; i < n; ++i) {
crypto.sign(
'sha256',
data,
{ key: privateKey || keys[i].privateKey, dsaEncoding: 'ieee-p1363' },
(err, signature) => {
crypto.verify(
'sha256',
data,
{ key: publicKey || keys[i].publicKey, dsaEncoding: 'ieee-p1363' },
signature,
done);
});
}
}
function main({ n, mode, keyFormat }) {
pems ||= [...Buffer.alloc(n)].map(() => ({
privateKey: keyFixtures.privateKey,
publicKey: keyFixtures.publicKey,
}));
keyObjects ||= pems.map(getKeyObject);
let privateKey, publicKey, keys;
switch (keyFormat) {
case 'keyObject':
({ publicKey, privateKey } = keyObjects[0]);
break;
case 'pem':
({ publicKey, privateKey } = pems[0]);
break;
case 'pem.unique':
keys = pems;
break;
case 'keyObject.unique':
keys = keyObjects;
break;
default:
throw new Error('not implemented');
}
switch (mode) {
case 'sync':
measureSync(n, privateKey, publicKey, keys);
break;
case 'async-serial':
measureAsyncSerial(n, privateKey, publicKey, keys);
break;
case 'async-parallel':
measureAsyncParallel(n, privateKey, publicKey, keys);
break;
}
}

View File

@ -0,0 +1,131 @@
'use strict';
const common = require('../common.js');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/');
const keyFixtures = {
ec: fs.readFileSync(`${fixtures_keydir}/ec_p256_private.pem`, 'utf-8'),
rsa: fs.readFileSync(`${fixtures_keydir}/rsa_private_2048.pem`, 'utf-8'),
ed25519: fs.readFileSync(`${fixtures_keydir}/ed25519_private.pem`, 'utf-8'),
};
const data = crypto.randomBytes(256);
let pems;
let keyObjects;
const bench = common.createBenchmark(main, {
keyType: ['rsa', 'ec', 'ed25519'],
mode: ['sync', 'async', 'async-parallel'],
keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'],
n: [1e3],
}, {
combinationFilter(p) {
// "keyObject.unique" allows to compare the result with "keyObject" to
// assess whether mutexes over the key material impact the operation
return p.keyFormat !== 'keyObject.unique' ||
(p.keyFormat === 'keyObject.unique' && p.mode === 'async-parallel');
},
});
function measureSync(n, digest, privateKey, keys) {
bench.start();
for (let i = 0; i < n; ++i) {
crypto.sign(
digest,
data,
privateKey || keys[i]);
}
bench.end(n);
}
function measureAsync(n, digest, privateKey, keys) {
let remaining = n;
function done() {
if (--remaining === 0)
bench.end(n);
else
one();
}
function one() {
crypto.sign(
digest,
data,
privateKey || keys[n - remaining],
done);
}
bench.start();
one();
}
function measureAsyncParallel(n, digest, privateKey, keys) {
let remaining = n;
function done() {
if (--remaining === 0)
bench.end(n);
}
bench.start();
for (let i = 0; i < n; ++i) {
crypto.sign(
digest,
data,
privateKey || keys[i],
done);
}
}
function main({ n, mode, keyFormat, keyType }) {
pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType]);
keyObjects ||= pems.map(crypto.createPrivateKey);
let privateKey, keys, digest;
switch (keyType) {
case 'rsa':
case 'ec':
digest = 'sha256';
break;
case 'ed25519':
break;
default:
throw new Error('not implemented');
}
switch (keyFormat) {
case 'keyObject':
privateKey = keyObjects[0];
break;
case 'pem':
privateKey = pems[0];
break;
case 'jwk': {
privateKey = { key: keyObjects[0].export({ format: 'jwk' }), format: 'jwk' };
break;
}
case 'der': {
privateKey = { key: keyObjects[0].export({ format: 'der', type: 'pkcs8' }), format: 'der', type: 'pkcs8' };
break;
}
case 'keyObject.unique':
keys = keyObjects;
break;
default:
throw new Error('not implemented');
}
switch (mode) {
case 'sync':
measureSync(n, digest, privateKey, keys);
break;
case 'async':
measureAsync(n, digest, privateKey, keys);
break;
case 'async-parallel':
measureAsyncParallel(n, digest, privateKey, keys);
break;
}
}

View File

@ -0,0 +1,151 @@
'use strict';
const common = require('../common.js');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/');
function readKey(name) {
return fs.readFileSync(`${fixtures_keydir}/${name}.pem`, 'utf8');
}
function readKeyPair(publicKeyName, privateKeyName) {
return {
publicKey: readKey(publicKeyName),
privateKey: readKey(privateKeyName),
};
}
const keyFixtures = {
ec: readKeyPair('ec_p256_public', 'ec_p256_private'),
rsa: readKeyPair('rsa_public_2048', 'rsa_private_2048'),
ed25519: readKeyPair('ed25519_public', 'ed25519_private'),
};
const data = crypto.randomBytes(256);
let pems;
let keyObjects;
const bench = common.createBenchmark(main, {
keyType: ['rsa', 'ec', 'ed25519'],
mode: ['sync', 'async', 'async-parallel'],
keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'],
n: [1e3],
}, {
combinationFilter(p) {
// "keyObject.unique" allows to compare the result with "keyObject" to
// assess whether mutexes over the key material impact the operation
return p.keyFormat !== 'keyObject.unique' ||
(p.keyFormat === 'keyObject.unique' && p.mode === 'async-parallel');
},
});
function measureSync(n, digest, signature, publicKey, keys) {
bench.start();
for (let i = 0; i < n; ++i) {
crypto.verify(
digest,
data,
publicKey || keys[i],
signature);
}
bench.end(n);
}
function measureAsync(n, digest, signature, publicKey, keys) {
let remaining = n;
function done() {
if (--remaining === 0)
bench.end(n);
else
one();
}
function one() {
crypto.verify(
digest,
data,
publicKey || keys[n - remaining],
signature,
done);
}
bench.start();
one();
}
function measureAsyncParallel(n, digest, signature, publicKey, keys) {
let remaining = n;
function done() {
if (--remaining === 0)
bench.end(n);
}
bench.start();
for (let i = 0; i < n; ++i) {
crypto.verify(
digest,
data,
publicKey || keys[i],
signature,
done);
}
}
function main({ n, mode, keyFormat, keyType }) {
pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType].publicKey);
keyObjects ||= pems.map(crypto.createPublicKey);
let publicKey, keys, digest;
switch (keyType) {
case 'rsa':
case 'ec':
digest = 'sha256';
break;
case 'ed25519':
break;
default:
throw new Error('not implemented');
}
switch (keyFormat) {
case 'keyObject':
publicKey = keyObjects[0];
break;
case 'pem':
publicKey = pems[0];
break;
case 'jwk': {
publicKey = { key: keyObjects[0].export({ format: 'jwk' }), format: 'jwk' };
break;
}
case 'der': {
publicKey = { key: keyObjects[0].export({ format: 'der', type: 'spki' }), format: 'der', type: 'spki' };
break;
}
case 'keyObject.unique':
keys = keyObjects;
break;
default:
throw new Error('not implemented');
}
const { privateKey } = keyFixtures[keyType];
const signature = crypto.sign(digest, data, privateKey);
switch (mode) {
case 'sync':
measureSync(n, digest, signature, publicKey, keys);
break;
case 'async':
measureAsync(n, digest, signature, publicKey, keys);
break;
case 'async-parallel':
measureAsyncParallel(n, digest, signature, publicKey, keys);
break;
default:
throw new Error('not implemented');
}
}