Imported upstream version 1.6.7
[platform/upstream/cryptsetup.git] / lib / utils_benchmark.c
index bb2319a..1e4469b 100644 (file)
@@ -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"
 
 #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++;