#include #include #include #include #include "../gettime.h" #include "../fio_time.h" #include "../lib/rand.h" #include "../os/os.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" #include "../crc/sha3.h" #include "../crc/xxhash.h" #include "../crc/murmur3.h" #include "../crc/fnv.h" #include "../hash.h" #include "test.h" #define CHUNK 131072U #define NR_CHUNKS 2048U struct test_type { const char *name; unsigned int mask; void (*fn)(struct test_type *, void *, size_t); uint32_t output; }; 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, T_XXHASH = 1U << 9, T_MURMUR3 = 1U << 10, T_JHASH = 1U << 11, T_FNV = 1U << 12, T_SHA3_224 = 1U << 13, T_SHA3_256 = 1U << 14, T_SHA3_384 = 1U << 15, T_SHA3_512 = 1U << 16, }; static void t_md5(struct test_type *t, void *buf, size_t size) { uint32_t digest[4]; struct fio_md5_ctx ctx = { .hash = digest }; int i; fio_md5_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) { fio_md5_update(&ctx, buf, size); fio_md5_final(&ctx); } } static void t_crc64(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += fio_crc64(buf, size); } static void t_crc32(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += fio_crc32(buf, size); } static void t_crc32c(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += fio_crc32c(buf, size); } static void t_crc16(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += fio_crc16(buf, size); } static void t_crc7(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += fio_crc7(buf, size); } static void t_sha1(struct test_type *t, void *buf, size_t size) { uint32_t sha[5]; struct fio_sha1_ctx ctx = { .H = sha }; int i; fio_sha1_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) { fio_sha1_update(&ctx, buf, size); fio_sha1_final(&ctx); } } static void t_sha256(struct test_type *t, void *buf, size_t size) { uint8_t sha[64]; struct fio_sha256_ctx ctx = { .buf = sha }; int i; fio_sha256_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) { fio_sha256_update(&ctx, buf, size); fio_sha256_final(&ctx); } } static void t_sha512(struct test_type *t, void *buf, size_t size) { uint8_t sha[128]; struct fio_sha512_ctx ctx = { .buf = sha }; int i; fio_sha512_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) fio_sha512_update(&ctx, buf, size); } static void t_sha3_224(struct test_type *t, void *buf, size_t size) { uint8_t sha[SHA3_224_DIGEST_SIZE]; struct fio_sha3_ctx ctx = { .sha = sha }; int i; fio_sha3_224_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) { fio_sha3_update(&ctx, buf, size); fio_sha3_final(&ctx); } } static void t_sha3_256(struct test_type *t, void *buf, size_t size) { uint8_t sha[SHA3_256_DIGEST_SIZE]; struct fio_sha3_ctx ctx = { .sha = sha }; int i; fio_sha3_256_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) { fio_sha3_update(&ctx, buf, size); fio_sha3_final(&ctx); } } static void t_sha3_384(struct test_type *t, void *buf, size_t size) { uint8_t sha[SHA3_384_DIGEST_SIZE]; struct fio_sha3_ctx ctx = { .sha = sha }; int i; fio_sha3_384_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) { fio_sha3_update(&ctx, buf, size); fio_sha3_final(&ctx); } } static void t_sha3_512(struct test_type *t, void *buf, size_t size) { uint8_t sha[SHA3_512_DIGEST_SIZE]; struct fio_sha3_ctx ctx = { .sha = sha }; int i; fio_sha3_512_init(&ctx); for (i = 0; i < NR_CHUNKS; i++) { fio_sha3_update(&ctx, buf, size); fio_sha3_final(&ctx); } } static void t_murmur3(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += murmurhash3(buf, size, 0x8989); } static void t_jhash(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += jhash(buf, size, 0x8989); } static void t_fnv(struct test_type *t, void *buf, size_t size) { int i; for (i = 0; i < NR_CHUNKS; i++) t->output += fnv(buf, size, 0x8989); } static void t_xxhash(struct test_type *t, void *buf, size_t size) { void *state; int i; state = XXH32_init(0x8989); for (i = 0; i < NR_CHUNKS; i++) XXH32_update(state, buf, size); t->output = XXH32_digest(state); } 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 = "xxhash", .mask = T_XXHASH, .fn = t_xxhash, }, { .name = "murmur3", .mask = T_MURMUR3, .fn = t_murmur3, }, { .name = "jhash", .mask = T_JHASH, .fn = t_jhash, }, { .name = "fnv", .mask = T_FNV, .fn = t_fnv, }, { .name = "sha3-224", .mask = T_SHA3_224, .fn = t_sha3_224, }, { .name = "sha3-256", .mask = T_SHA3_256, .fn = t_sha3_256, }, { .name = "sha3-384", .mask = T_SHA3_384, .fn = t_sha3_384, }, { .name = "sha3-512", .mask = T_SHA3_512, .fn = t_sha3_512, }, { .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 (!strcmp(t[i].name, name)) { mask |= t[i].mask; break; } } } free(ostr); return mask; } static int list_types(void) { int i; for (i = 0; t[i].name; i++) printf("%s\n", t[i].name); return 1; } int fio_crctest(const char *type) { unsigned int test_mask = 0; uint64_t mb = CHUNK * NR_CHUNKS; struct frand_state state; int i, first = 1; void *buf; crc32c_arm64_probe(); crc32c_intel_probe(); if (!type) test_mask = ~0U; else if (!strcmp(type, "help") || !strcmp(type, "list")) return list_types(); else test_mask = get_test_mask(type); if (!test_mask) { fprintf(stderr, "fio: unknown hash `%s`. Available:\n", type); return list_types(); } buf = malloc(CHUNK); init_rand_seed(&state, 0x8989, 0); fill_random_buf(&state, buf, CHUNK); for (i = 0; t[i].name; i++) { struct timespec ts; double mb_sec; uint64_t usec; char pre[3]; if (!(t[i].mask & test_mask)) continue; /* * For first run, make sure CPUs are spun up and that * we've touched the data. */ if (first) { usec_spin(100000); t[i].fn(&t[i], buf, CHUNK); } fio_gettime(&ts, NULL); t[i].fn(&t[i], buf, CHUNK); usec = utime_since_now(&ts); if (usec) { mb_sec = (double) mb / (double) usec; mb_sec /= (1.024 * 1.024); if (strlen(t[i].name) >= 7) sprintf(pre, "\t"); else sprintf(pre, "\t\t"); printf("%s:%s%8.2f MiB/sec\n", t[i].name, pre, mb_sec); } else printf("%s:inf MiB/sec\n", t[i].name); first = 0; } free(buf); return 0; }