2 * libcryptsetup - cryptsetup library, cipher bechmark
4 * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2012, Milan Broz
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <sys/resource.h>
29 * This is not simulating storage, so using disk block causes extreme overhead.
30 * Let's use some fixed block size where results are more reliable...
32 #define CIPHER_BLOCK_BYTES 65536
35 * The whole test depends on Linux kernel usermode crypto API for now.
36 * (The same implementations are used in dm-crypt though.)
49 static long time_ms(struct rusage *start, struct rusage *end)
53 /* For kernel backend, we need to measure only tim in kernel.
54 ms = (end->ru_utime.tv_sec - start->ru_utime.tv_sec) * 1000;
55 ms += (end->ru_utime.tv_usec - start->ru_utime.tv_usec) / 1000;
58 ms += (end->ru_stime.tv_sec - start->ru_stime.tv_sec) * 1000;
59 ms += (end->ru_stime.tv_usec - start->ru_stime.tv_usec) / 1000;
64 static int cipher_perf_one(struct cipher_perf *cp, char *buf,
65 size_t buf_size, int enc)
67 struct crypt_cipher *cipher = NULL;
68 size_t done = 0, block = CIPHER_BLOCK_BYTES;
74 r = crypt_cipher_init(&cipher, cp->name, cp->mode, cp->key, cp->key_length);
76 log_dbg("Cannot initialise cipher %s, mode %s.", cp->name, cp->mode);
80 while (done < buf_size) {
81 if ((done + block) > buf_size)
82 block = buf_size - done;
85 r = crypt_cipher_encrypt(cipher, &buf[done], &buf[done],
86 block, cp->iv, cp->iv_length);
88 r = crypt_cipher_decrypt(cipher, &buf[done], &buf[done],
89 block, cp->iv, cp->iv_length);
96 crypt_cipher_destroy(cipher);
100 static long cipher_measure(struct cipher_perf *cp, char *buf,
101 size_t buf_size, int encrypt)
103 struct rusage rstart, rend;
106 if (getrusage(RUSAGE_SELF, &rstart) < 0)
109 r = cipher_perf_one(cp, buf, buf_size, encrypt);
113 if (getrusage(RUSAGE_SELF, &rend) < 0)
116 return time_ms(&rstart, &rend);
119 static double speed_mbs(unsigned long bytes, unsigned long ms)
121 double speed = bytes, s = ms / 1000.;
123 return speed / (1024 * 1024) / s;
126 static int cipher_perf(struct cipher_perf *cp,
127 double *encryption_mbs, double *decryption_mbs)
129 long ms_enc, ms_dec, ms;
130 int repeat_enc, repeat_dec;
133 if (posix_memalign(&buf, crypt_getpagesize(), cp->buffer_size))
138 while (ms_enc < 1000) {
139 ms = cipher_measure(cp, buf, cp->buffer_size, 1);
150 while (ms_dec < 1000) {
151 ms = cipher_measure(cp, buf, cp->buffer_size, 0);
162 *encryption_mbs = speed_mbs(cp->buffer_size * repeat_enc, ms_enc);
163 *decryption_mbs = speed_mbs(cp->buffer_size * repeat_dec, ms_dec);
168 int crypt_benchmark(struct crypt_device *cd,
170 const char *cipher_mode,
171 size_t volume_key_size,
174 double *encryption_mbs,
175 double *decryption_mbs)
177 struct cipher_perf cp = {
178 .key_length = volume_key_size,
179 .iv_length = iv_size,
180 .buffer_size = buffer_size,
185 if (!cipher || !cipher_mode || !volume_key_size)
194 cp.iv = malloc(iv_size);
197 crypt_random_get(cd, cp.iv, iv_size, CRYPT_RND_NORMAL);
200 cp.key = malloc(volume_key_size);
204 crypt_random_get(cd, cp.key, volume_key_size, CRYPT_RND_NORMAL);
205 strncpy(cp.name, cipher, sizeof(cp.name)-1);
206 strncpy(cp.mode, cipher_mode, sizeof(cp.mode)-1);
208 /* Ignore IV generator */
209 if ((c = strchr(cp.mode, '-')))
212 r = cipher_perf(&cp, encryption_mbs, decryption_mbs);