btrfs-progs: crypto: add time-based measurement to hash-speedtest

People are interested in measuring the hash performance on non-x86_64
architectures. Add option to do time-based measurements (in nanoseconds)
in case there's no support for clock-based measurements.

  $ ./hash-speedtest --cycles
  Block size:     4096
  Iterations:     100000
  Implementation: builtin
  Units:          cycles

      NULL-NOP: cycles:     43035633, cycles/i      430
   NULL-MEMCPY: cycles:     72478624, cycles/i      724
	CRC32C: cycles:    181712982, cycles/i     1817
	XXHASH: cycles:    136251305, cycles/i     1362
	SHA256: cycles:  10758567410, cycles/i   107585
       BLAKE2b: cycles:   2249704806, cycles/i    22497

  $ ./hash-speedtest --time
  Block size:     4096
  Iterations:     100000
  Implementation: builtin
  Units:          nsecs

      NULL-NOP:  nsecs:     12459033, nsecs/i      124
   NULL-MEMCPY:  nsecs:     20687845, nsecs/i      206
	CRC32C:  nsecs:     52648264, nsecs/i      526
	XXHASH:  nsecs:     39591766, nsecs/i      395
	SHA256:  nsecs:   3079668837, nsecs/i    30796
       BLAKE2b:  nsecs:    644766582, nsecs/i     6447

Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2021-05-26 20:22:55 +02:00
parent f123c28412
commit 55bf9b749d
2 changed files with 73 additions and 7 deletions

View File

@ -58,6 +58,8 @@ AC_CHECK_FUNCS([openat], [],
AC_CHECK_FUNCS([reallocarray])
AC_CHECK_FUNCS([clock_gettime])
m4_ifndef([PKG_PROG_PKG_CONFIG],
[m4_fatal([Could not locate the pkg-config autoconf
macros. These are usually located in /usr/share/aclocal/pkg.m4.

View File

@ -1,16 +1,21 @@
#include "../kerncompat.h"
#include <time.h>
#include <getopt.h>
#include "crypto/hash.h"
#include "crypto/crc32c.h"
#include "crypto/sha.h"
#include "crypto/blake2.h"
#ifndef __x86_64__
#error "Only x86_64 supported"
#ifdef __x86_64__
static const int cycles_supported = 1;
#else
static const int cycles_supported = 0;
#endif
const int blocksize = 4096;
int iterations = 100000;
#ifdef __x86_64__
static __always_inline unsigned long long rdtsc(void)
{
unsigned low, high;
@ -26,6 +31,22 @@ static inline u64 read_tsc(void)
return rdtsc();
}
#define get_cycles() read_tsc()
#else
#define get_cycles() (0)
#endif
static inline u64 get_time(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
}
/* Read the input and copy last bytes as the hash */
static int hash_null_memcpy(const u8 *buf, size_t length, u8 *out)
{
@ -47,6 +68,15 @@ static int hash_null_nop(const u8 *buf, size_t length, u8 *out)
return 0;
}
const char *units_to_str(int units)
{
switch (units) {
case 0: return "cycles";
case 1: return "nsecs";
}
return "unknown";
}
int main(int argc, char **argv) {
u8 buf[blocksize];
u8 hash[32];
@ -65,9 +95,40 @@ int main(int argc, char **argv) {
{ .name = "SHA256", .digest = hash_sha256, .digest_size = 32 },
{ .name = "BLAKE2b", .digest = hash_blake2b, .digest_size = 32 },
};
int units = 0;
if (argc > 1) {
iterations = atoi(argv[1]);
optind = 0;
while (1) {
static const struct option long_options[] = {
{ "cycles", no_argument, NULL, 'c' },
{ "time", no_argument, NULL, 't' },
{ NULL, 0, NULL, 0}
};
int c;
c = getopt_long(argc, argv, "ct", long_options, NULL);
if (c < 0)
break;
switch (c) {
case 'c':
if (!cycles_supported) {
fprintf(stderr,
"ERROR: cannot measure cycles on this arch, use --time\n");
return 1;
}
units = 0;
break;
case 't':
units = 1;
break;
default:
fprintf(stderr, "ERROR: unknown option\n");
return 1;
}
}
if (argc - optind >= 1) {
iterations = atoi(argv[optind]);
if (iterations < 0)
iterations = 1;
}
@ -78,6 +139,7 @@ int main(int argc, char **argv) {
printf("Block size: %d\n", blocksize);
printf("Iterations: %d\n", iterations);
printf("Implementation: %s\n", CRYPTOPROVIDER);
printf("Units: %s\n", units_to_str(units));
printf("\n");
for (idx = 0; idx < ARRAY_SIZE(contestants); idx++) {
@ -87,17 +149,19 @@ int main(int argc, char **argv) {
printf("% 12s: ", c->name);
fflush(stdout);
start = read_tsc();
start = (units ? get_time() : get_cycles());
for (iter = 0; iter < iterations; iter++) {
memset(buf, iter & 0xFF, blocksize);
memset(hash, 0, 32);
c->digest(buf, blocksize, hash);
}
end = read_tsc();
end = (units ? get_time() : get_cycles());
c->cycles = end - start;
printf("cycles: % 12llu, c/i % 8llu\n",
printf("%: % 12llu, %s/i % 8llu\n",
units_to_str(units),
(unsigned long long)c->cycles,
units_to_str(units),
(unsigned long long)c->cycles / iterations);
}