aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Broz <gmazyland@gmail.com>2013-12-01 10:55:35 +0100
committerMilan Broz <gmazyland@gmail.com>2013-12-01 10:55:35 +0100
commitf3e398afc54948fd95a811e0270bbdd5d5689efd (patch)
tree1fc006246fa553c9244ed18720fd9adeedd7d4ab
parent65877efe8b08e301e8a14739cbd97f22b757aad5 (diff)
downloadcryptsetup-f3e398afc54948fd95a811e0270bbdd5d5689efd.tar.gz
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.
-rw-r--r--TODO2
-rw-r--r--lib/libcryptsetup.h3
-rw-r--r--lib/utils_benchmark.c78
-rw-r--r--src/cryptsetup.c34
4 files changed, 79 insertions, 38 deletions
diff --git a/TODO b/TODO
index edf3089..3b06824 100644
--- a/TODO
+++ b/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)
diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h
index 2a1ca06..e008907 100644
--- a/lib/libcryptsetup.h
+++ b/lib/libcryptsetup.h
@@ -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,
diff --git a/lib/utils_benchmark.c b/lib/utils_benchmark.c
index bb2319a..1e4469b 100644
--- a/lib/utils_benchmark.c
+++ b/lib/utils_benchmark.c
@@ -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"
@@ -33,6 +32,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++;
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index 85fd11f..abdd117 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -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;