diff --git a/Makefile b/Makefile index fd99fb5c..37f47a28 100644 --- a/Makefile +++ b/Makefile @@ -646,6 +646,10 @@ fssum: tests/fssum.c crypto/sha224-256.c @echo " [LD] $@" $(Q)$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) +hash-speedtest: crypto/hash-speedtest.c $(objects) $(libs_static) + @echo " [LD] $@" + $(Q)$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) + test-build: test-build-pre test-build-real test-build-pre: diff --git a/crypto/hash-speedtest.c b/crypto/hash-speedtest.c new file mode 100644 index 00000000..c3f6bbc8 --- /dev/null +++ b/crypto/hash-speedtest.c @@ -0,0 +1,100 @@ +#include "../kerncompat.h" +#include "crypto/hash.h" +#include "crypto/crc32c.h" + +#ifndef __x86_64__ +#error "Only x86_64 supported" +#endif + +const int blocksize = 4096; +int iterations = 100000; + +static __always_inline unsigned long long rdtsc(void) +{ + unsigned low, high; + + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + + return (low | ((u64)(high) << 32)); +} + +static inline u64 read_tsc(void) +{ + asm volatile("mfence"); + return rdtsc(); +} + +/* Read the input and copy last bytes as the hash */ +static int hash_null_memcpy(const u8 *buf, size_t length, u8 *out) +{ + const u8 *end = buf + length; + + while (buf + CRYPTO_HASH_SIZE_MAX < end) { + memcpy(out, buf, CRYPTO_HASH_SIZE_MAX); + buf += CRYPTO_HASH_SIZE_MAX; + } + + return 0; +} + +/* Test overhead of the calls */ +static int hash_null_nop(const u8 *buf, size_t length, u8 *out) +{ + memset(out, 0xFF, CRYPTO_HASH_SIZE_MAX); + + return 0; +} + +int main(int argc, char **argv) { + u8 buf[blocksize]; + u8 hash[32]; + int idx; + int iter; + struct contestant { + char name[16]; + int (*digest)(const u8 *buf, size_t length, u8 *out); + int digest_size; + u64 cycles; + } contestants[] = { + { .name = "NULL-NOP", .digest = hash_null_nop, .digest_size = 32 }, + { .name = "NULL-MEMCPY", .digest = hash_null_memcpy, .digest_size = 32 }, + { .name = "CRC32C", .digest = hash_crc32c, .digest_size = 4 }, + { .name = "XXHASH", .digest = hash_xxhash, .digest_size = 8 }, + }; + + if (argc > 1) { + iterations = atoi(argv[1]); + if (iterations < 0) + iterations = 1; + } + + crc32c_optimization_init(); + memset(buf, 0, 4096); + + printf("Block size: %d\n", blocksize); + printf("Iterations: %d\n", iterations); + printf("\n"); + + for (idx = 0; idx < ARRAY_SIZE(contestants); idx++) { + struct contestant *c = &contestants[idx]; + u64 start, end; + + printf("% 12s: ", c->name); + fflush(stdout); + + start = read_tsc(); + for (iter = 0; iter < iterations; iter++) { + memset(buf, iter & 0xFF, blocksize); + memset(hash, 0, 32); + c->digest(buf, blocksize, hash); + } + end = read_tsc(); + c->cycles = end - start; + + printf("cycles: % 12llu, c/i % 8llu\n", + (unsigned long long)c->cycles, + (unsigned long long)c->cycles / iterations); + } + + return 0; +}