mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Rewrite cipher benchmark loop.
Using getrusage seems toi give not adequate precision, so use clock_gettime and try to scale buffer size a bit on high performance systems. If it still fail, return ERANGE error instead calculating completely unreliable numbers. Should fix Issue#186.
This commit is contained in:
2
TODO
2
TODO
@@ -6,3 +6,5 @@ Version 1.7:
|
||||
- Resync ETA time is not accurate, calculate it better (last minute window?).
|
||||
- Crypt benchmark cannot ttest ECB mode.
|
||||
- Log doesn't work yet in early binary start (FIPS message).
|
||||
|
||||
- crypto backend should initialise itself only once (debug log)
|
||||
|
||||
@@ -1019,6 +1019,9 @@ int crypt_get_verity_info(struct crypt_device *cd,
|
||||
* @param decryption_mbs measured decryption speed in MiB/s
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note If encryption_buffer_size is too small and encryption time
|
||||
* cannot be properly measured, -ERANGE is returned.
|
||||
*/
|
||||
int crypt_benchmark(struct crypt_device *cd,
|
||||
const char *cipher,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* libcryptsetup - cryptsetup library, cipher bechmark
|
||||
*
|
||||
* Copyright (C) 2012, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012, Milan Broz
|
||||
* Copyright (C) 2012-2013, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -21,8 +21,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -32,6 +31,12 @@
|
||||
*/
|
||||
#define CIPHER_BLOCK_BYTES 65536
|
||||
|
||||
/*
|
||||
* If the measured value is lower, encrypted buffer is probably too small
|
||||
* and calculated values are not reliable.
|
||||
*/
|
||||
#define CIPHER_TIME_MIN_MS 0.001
|
||||
|
||||
/*
|
||||
* The whole test depends on Linux kernel usermode crypto API for now.
|
||||
* (The same implementations are used in dm-crypt though.)
|
||||
@@ -47,19 +52,15 @@ struct cipher_perf {
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
static long time_ms(struct rusage *start, struct rusage *end)
|
||||
static int time_ms(struct timespec *start, struct timespec *end, double *ms)
|
||||
{
|
||||
long ms = 0;
|
||||
double start_ms, end_ms;
|
||||
|
||||
/* For kernel backend, we need to measure only tim in kernel.
|
||||
ms = (end->ru_utime.tv_sec - start->ru_utime.tv_sec) * 1000;
|
||||
ms += (end->ru_utime.tv_usec - start->ru_utime.tv_usec) / 1000;
|
||||
*/
|
||||
start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
|
||||
end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
|
||||
|
||||
ms += (end->ru_stime.tv_sec - start->ru_stime.tv_sec) * 1000;
|
||||
ms += (end->ru_stime.tv_usec - start->ru_stime.tv_usec) / 1000;
|
||||
|
||||
return ms;
|
||||
*ms = end_ms - start_ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cipher_perf_one(struct cipher_perf *cp, char *buf,
|
||||
@@ -98,26 +99,39 @@ static int cipher_perf_one(struct cipher_perf *cp, char *buf,
|
||||
|
||||
return r;
|
||||
}
|
||||
static long cipher_measure(struct cipher_perf *cp, char *buf,
|
||||
size_t buf_size, int encrypt)
|
||||
static int cipher_measure(struct cipher_perf *cp, char *buf,
|
||||
size_t buf_size, int encrypt, double *ms)
|
||||
{
|
||||
struct rusage rstart, rend;
|
||||
struct timespec start, end;
|
||||
int r;
|
||||
|
||||
if (getrusage(RUSAGE_SELF, &rstart) < 0)
|
||||
/*
|
||||
* Using getrusage would be better here but the precision
|
||||
* is not adequate, so better stick with CLOCK_MONOTONIC
|
||||
*/
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = cipher_perf_one(cp, buf, buf_size, encrypt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (getrusage(RUSAGE_SELF, &rend) < 0)
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &end) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return time_ms(&rstart, &rend);
|
||||
r = time_ms(&start, &end, ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (*ms < CIPHER_TIME_MIN_MS) {
|
||||
log_dbg("Measured cipher runtime (%1.6f) is too low.", *ms);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static double speed_mbs(unsigned long bytes, unsigned long ms)
|
||||
static double speed_mbs(unsigned long bytes, double ms)
|
||||
{
|
||||
double speed = bytes, s = ms / 1000.;
|
||||
|
||||
@@ -127,32 +141,32 @@ static double speed_mbs(unsigned long bytes, unsigned long ms)
|
||||
static int cipher_perf(struct cipher_perf *cp,
|
||||
double *encryption_mbs, double *decryption_mbs)
|
||||
{
|
||||
long ms_enc, ms_dec, ms;
|
||||
int repeat_enc, repeat_dec;
|
||||
double ms_enc, ms_dec, ms;
|
||||
int r, repeat_enc, repeat_dec;
|
||||
void *buf = NULL;
|
||||
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), cp->buffer_size))
|
||||
return -ENOMEM;
|
||||
|
||||
ms_enc = 0;
|
||||
ms_enc = 0.0;
|
||||
repeat_enc = 1;
|
||||
while (ms_enc < 1000) {
|
||||
ms = cipher_measure(cp, buf, cp->buffer_size, 1);
|
||||
if (ms < 0) {
|
||||
while (ms_enc < 1000.0) {
|
||||
r = cipher_measure(cp, buf, cp->buffer_size, 1, &ms);
|
||||
if (r < 0) {
|
||||
free(buf);
|
||||
return (int)ms;
|
||||
return r;
|
||||
}
|
||||
ms_enc += ms;
|
||||
repeat_enc++;
|
||||
}
|
||||
|
||||
ms_dec = 0;
|
||||
ms_dec = 0.0;
|
||||
repeat_dec = 1;
|
||||
while (ms_dec < 1000) {
|
||||
ms = cipher_measure(cp, buf, cp->buffer_size, 0);
|
||||
if (ms < 0) {
|
||||
while (ms_dec < 1000.0) {
|
||||
r = cipher_measure(cp, buf, cp->buffer_size, 0, &ms);
|
||||
if (r < 0) {
|
||||
free(buf);
|
||||
return (int)ms;
|
||||
return r;
|
||||
}
|
||||
ms_dec += ms;
|
||||
repeat_dec++;
|
||||
|
||||
@@ -460,6 +460,29 @@ static int action_benchmark_kdf(const char *hash)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int benchmark_cipher_loop(const char *cipher, const char *cipher_mode,
|
||||
size_t volume_key_size, size_t iv_size,
|
||||
double *encryption_mbs, double *decryption_mbs)
|
||||
{
|
||||
int r, buffer_size = 1024 * 1024;
|
||||
|
||||
do {
|
||||
r = crypt_benchmark(NULL, cipher, cipher_mode,
|
||||
volume_key_size, iv_size, buffer_size,
|
||||
encryption_mbs, decryption_mbs);
|
||||
if (r == -ERANGE) {
|
||||
if (buffer_size < 1024 * 1024 * 65)
|
||||
buffer_size *= 2;
|
||||
else {
|
||||
log_err(_("Result of benchmark is not reliable.\n"));
|
||||
r = -ENOENT;
|
||||
}
|
||||
}
|
||||
} while (r == -ERANGE);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int action_benchmark(void)
|
||||
{
|
||||
static struct {
|
||||
@@ -489,7 +512,6 @@ static int action_benchmark(void)
|
||||
double enc_mbr = 0, dec_mbr = 0;
|
||||
int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS);
|
||||
int iv_size = 16, skipped = 0;
|
||||
int buffer_size = 1024 * 1024;
|
||||
char *c;
|
||||
int i, r;
|
||||
|
||||
@@ -511,9 +533,9 @@ static int action_benchmark(void)
|
||||
strstr(cipher, "cast5"))
|
||||
iv_size = 8;
|
||||
|
||||
r = crypt_benchmark(NULL, cipher, cipher_mode,
|
||||
key_size / 8, iv_size, buffer_size,
|
||||
&enc_mbr, &dec_mbr);
|
||||
r = benchmark_cipher_loop(cipher, cipher_mode,
|
||||
key_size / 8, iv_size,
|
||||
&enc_mbr, &dec_mbr);
|
||||
if (!r) {
|
||||
log_std(N_("# Algorithm | Key | Encryption | Decryption\n"));
|
||||
log_std("%8s-%s %4db %6.1f MiB/s %6.1f MiB/s\n",
|
||||
@@ -528,9 +550,9 @@ static int action_benchmark(void)
|
||||
break;
|
||||
}
|
||||
for (i = 0; bciphers[i].cipher; i++) {
|
||||
r = crypt_benchmark(NULL, bciphers[i].cipher, bciphers[i].mode,
|
||||
r = benchmark_cipher_loop(bciphers[i].cipher, bciphers[i].mode,
|
||||
bciphers[i].key_size, bciphers[i].iv_size,
|
||||
buffer_size, &enc_mbr, &dec_mbr);
|
||||
&enc_mbr, &dec_mbr);
|
||||
check_signal(&r);
|
||||
if (r == -ENOTSUP || r == -EINTR)
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user