Add support for testing checksumming speed
authorJens Axboe <axboe@fb.com>
Fri, 7 Feb 2014 21:39:33 +0000 (14:39 -0700)
committerJens Axboe <axboe@fb.com>
Fri, 7 Feb 2014 21:39:33 +0000 (14:39 -0700)
fio --crctest will test all of them, --crctest=md5,crc32c will
test md5 and crc32c, for example.

Signed-off-by: Jens Axboe <axboe@fb.com>
crc/test.c [new file with mode: 0644]
fio.1
init.c

diff --git a/crc/test.c b/crc/test.c
new file mode 100644 (file)
index 0000000..2ea4f3d
--- /dev/null
@@ -0,0 +1,335 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../fio.h"
+#include "../gettime.h"
+#include "../time.h"
+#include "../verify.h"
+
+#include "../crc/md5.h"
+#include "../crc/crc64.h"
+#include "../crc/crc32.h"
+#include "../crc/crc32c.h"
+#include "../crc/crc16.h"
+#include "../crc/crc7.h"
+#include "../crc/sha1.h"
+#include "../crc/sha256.h"
+#include "../crc/sha512.h"
+
+#define CHUNK          131072
+#define NR_CHUNKS        2048
+
+struct test_type {
+       const char *name;
+       unsigned int mask;
+       uint64_t (*fn)(void);
+};
+
+enum {
+       T_MD5           = 1U << 0,
+       T_CRC64         = 1U << 1,
+       T_CRC32         = 1U << 2,
+       T_CRC32C        = 1U << 3,
+       T_CRC16         = 1U << 4,
+       T_CRC7          = 1U << 5,
+       T_SHA1          = 1U << 6,
+       T_SHA256        = 1U << 7,
+       T_SHA512        = 1U << 8,
+};
+
+static void randomize_buf(void *buf, unsigned int size, int seed)
+{
+       struct frand_state state;
+
+       init_rand_seed(&state, seed);
+       fill_random_buf(&state, buf, size);
+}
+
+static uint64_t t_md5(void)
+{
+       uint32_t digest[4];
+       struct fio_md5_ctx ctx = { .hash = digest };
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       fio_md5_init(&ctx);
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_md5_update(&ctx, buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_crc64(void)
+{
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_crc64(buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_crc32(void)
+{
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_crc32(buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_crc32c(void)
+{
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_crc32c(buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_crc16(void)
+{
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_crc16(buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_crc7(void)
+{
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_crc7(buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_sha1(void)
+{
+       uint32_t sha[5];
+       struct fio_sha1_ctx ctx = { .H = sha };
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       fio_sha1_init(&ctx);
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_sha1_update(&ctx, buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_sha256(void)
+{
+       uint8_t sha[64];
+       struct fio_sha256_ctx ctx = { .buf = sha };
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       fio_sha256_init(&ctx);
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_sha256_update(&ctx, buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static uint64_t t_sha512(void)
+{
+       uint8_t sha[128];
+       struct fio_sha512_ctx ctx = { .buf = sha };
+       struct timeval s;
+       uint64_t ret;
+       void *buf;
+       int i;
+
+       fio_sha512_init(&ctx);
+
+       buf = malloc(CHUNK);
+       randomize_buf(buf, CHUNK, 0x8989);
+
+       fio_gettime(&s, NULL);
+       for (i = 0; i < NR_CHUNKS; i++)
+               fio_sha512_update(&ctx, buf, CHUNK);
+
+       ret = utime_since_now(&s);
+       free(buf);
+       return ret;
+}
+
+static struct test_type t[] = {
+       {
+               .name = "md5",
+               .mask = T_MD5,
+               .fn = t_md5,
+       },
+       {
+               .name = "crc64",
+               .mask = T_CRC64,
+               .fn = t_crc64,
+       },
+       {
+               .name = "crc32",
+               .mask = T_CRC32,
+               .fn = t_crc32,
+       },
+       {
+               .name = "crc32c",
+               .mask = T_CRC32C,
+               .fn = t_crc32c,
+       },
+       {
+               .name = "crc16",
+               .mask = T_CRC16,
+               .fn = t_crc16,
+       },
+       {
+               .name = "crc7",
+               .mask = T_CRC7,
+               .fn = t_crc7,
+       },
+       {
+               .name = "sha1",
+               .mask = T_SHA1,
+               .fn = t_sha1,
+       },
+       {
+               .name = "sha256",
+               .mask = T_SHA256,
+               .fn = t_sha256,
+       },
+       {
+               .name = "sha512",
+               .mask = T_SHA512,
+               .fn = t_sha512,
+       },
+       {
+               .name = NULL,
+       },
+};
+
+static unsigned int get_test_mask(const char *type)
+{
+       char *ostr, *str = strdup(type);
+       unsigned int mask;
+       char *name;
+       int i;
+
+       ostr = str;
+       mask = 0;
+       while ((name = strsep(&str, ",")) != NULL) {
+               for (i = 0; t[i].name; i++) {
+                       if (!strncmp(t[i].name, name, strlen(t[i].name))) {
+                               mask |= t[i].mask;
+                               break;
+                       }
+               }
+       }
+
+       free(ostr);
+       return mask;
+}
+
+int fio_crctest(const char *type)
+{
+       unsigned int test_mask = 0;
+       uint64_t mb = CHUNK * NR_CHUNKS;
+       int i;
+
+       crc32c_intel_probe();
+
+       if (!type)
+               test_mask = ~0U;
+       else
+               test_mask = get_test_mask(type);
+
+       for (i = 0; t[i].name; i++) {
+               double mb_sec;
+               uint64_t usec;
+
+               if (!(t[i].mask & test_mask))
+                       continue;
+
+               usec = t[i].fn();
+               mb_sec = (double) mb / (double) usec;
+               mb_sec /= (1.024 * 1.024);
+               printf("%s:\t%.2f MB/sec\n", t[i].name, mb_sec);
+       }
+       return 0;
+}
diff --git a/fio.1 b/fio.1
index 3cdfd27b46f416886a83771af2bfc741e01456e7..ec103776afc274d4467e322904a9ad0f23f11f89 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -41,6 +41,14 @@ Set terse version output format (Current version 3, or older version 2).
 .B \-\-help
 Display usage information and exit.
 .TP
+.B \-\-cpuclock-test
+Perform test and validation of internal CPU clock
+.TP
+.BI \-\-crctest[\fR=\fPtest]
+Test the speed of the builtin checksumming functions. If no argument is given,
+all of them are tested. Or a comma separated list can be passed, in which
+case the given ones are tested.
+.TP
 .BI \-\-cmdhelp \fR=\fPcommand
 Print help information for \fIcommand\fR.  May be `all' for all commands.
 .TP
diff --git a/init.c b/init.c
index 6c48d3ad8a9cd278b9dbf911a2436192f28a61aa..b26dc9fe30681eeff07f2e5c5882ebac8e1f586d 100644 (file)
--- a/init.c
+++ b/init.c
@@ -207,6 +207,11 @@ static struct option l_opts[FIO_NR_OPTIONS] = {
                .has_arg        = no_argument,
                .val            = 'T',
        },
+       {
+               .name           = (char *) "crctest",
+               .has_arg        = optional_argument,
+               .val            = 'G',
+       },
        {
                .name           = (char *) "idle-prof",
                .has_arg        = required_argument,
@@ -1405,6 +1410,7 @@ static void usage(const char *name)
        printf("  --version\t\tPrint version info and exit\n");
        printf("  --help\t\tPrint this page\n");
        printf("  --cpuclock-test\tPerform test/validation of CPU clock\n");
+       printf("  --crctest\t\tTest speed of checksum functions\n");
        printf("  --cmdhelp=cmd\t\tPrint command help, \"all\" for all of"
                " them\n");
        printf("  --enghelp=engine\tPrint ioengine help, or list"
@@ -1604,6 +1610,8 @@ void parse_cmd_client(void *client, char *opt)
        fio_client_add_cmd_option(client, opt);
 }
 
+extern int fio_crctest(const char *);
+
 int parse_cmd_line(int argc, char *argv[], int client_type)
 {
        struct thread_data *td = NULL;
@@ -1868,6 +1876,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        do_exit++;
                        exit_val = fio_monotonic_clocktest();
                        break;
+               case 'G':
+                       do_exit++;
+                       exit_val = fio_crctest(optarg);
+                       break;
                case 'L': {
                        long long val;