+#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;
+}