diff options
author | Milan Broz <gmazyland@gmail.com> | 2013-12-01 10:55:35 +0100 |
---|---|---|
committer | Milan Broz <gmazyland@gmail.com> | 2013-12-01 10:55:35 +0100 |
commit | f3e398afc54948fd95a811e0270bbdd5d5689efd (patch) | |
tree | 1fc006246fa553c9244ed18720fd9adeedd7d4ab | |
parent | 65877efe8b08e301e8a14739cbd97f22b757aad5 (diff) | |
download | cryptsetup-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-- | TODO | 2 | ||||
-rw-r--r-- | lib/libcryptsetup.h | 3 | ||||
-rw-r--r-- | lib/utils_benchmark.c | 78 | ||||
-rw-r--r-- | src/cryptsetup.c | 34 |
4 files changed, 79 insertions, 38 deletions
@@ -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; |