1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#include "../fio.h" 6#include "../gettime.h" 7#include "../fio_time.h" 8#include "../verify.h" 9 10#include "../crc/md5.h" 11#include "../crc/crc64.h" 12#include "../crc/crc32.h" 13#include "../crc/crc32c.h" 14#include "../crc/crc16.h" 15#include "../crc/crc7.h" 16#include "../crc/sha1.h" 17#include "../crc/sha256.h" 18#include "../crc/sha512.h" 19#include "../crc/sha3.h" 20#include "../crc/xxhash.h" 21#include "../crc/murmur3.h" 22#include "../crc/fnv.h" 23#include "../hash.h" 24 25#include "test.h" 26 27#define CHUNK 131072U 28#define NR_CHUNKS 2048U 29 30struct test_type { 31 const char *name; 32 unsigned int mask; 33 void (*fn)(struct test_type *, void *, size_t); 34 uint32_t output; 35}; 36 37enum { 38 T_MD5 = 1U << 0, 39 T_CRC64 = 1U << 1, 40 T_CRC32 = 1U << 2, 41 T_CRC32C = 1U << 3, 42 T_CRC16 = 1U << 4, 43 T_CRC7 = 1U << 5, 44 T_SHA1 = 1U << 6, 45 T_SHA256 = 1U << 7, 46 T_SHA512 = 1U << 8, 47 T_XXHASH = 1U << 9, 48 T_MURMUR3 = 1U << 10, 49 T_JHASH = 1U << 11, 50 T_FNV = 1U << 12, 51 T_SHA3_224 = 1U << 13, 52 T_SHA3_256 = 1U << 14, 53 T_SHA3_384 = 1U << 15, 54 T_SHA3_512 = 1U << 16, 55}; 56 57static void t_md5(struct test_type *t, void *buf, size_t size) 58{ 59 uint32_t digest[4]; 60 struct fio_md5_ctx ctx = { .hash = digest }; 61 int i; 62 63 fio_md5_init(&ctx); 64 65 for (i = 0; i < NR_CHUNKS; i++) { 66 fio_md5_update(&ctx, buf, size); 67 fio_md5_final(&ctx); 68 } 69} 70 71static void t_crc64(struct test_type *t, void *buf, size_t size) 72{ 73 int i; 74 75 for (i = 0; i < NR_CHUNKS; i++) 76 t->output += fio_crc64(buf, size); 77} 78 79static void t_crc32(struct test_type *t, void *buf, size_t size) 80{ 81 int i; 82 83 for (i = 0; i < NR_CHUNKS; i++) 84 t->output += fio_crc32(buf, size); 85} 86 87static void t_crc32c(struct test_type *t, void *buf, size_t size) 88{ 89 int i; 90 91 for (i = 0; i < NR_CHUNKS; i++) 92 t->output += fio_crc32c(buf, size); 93} 94 95static void t_crc16(struct test_type *t, void *buf, size_t size) 96{ 97 int i; 98 99 for (i = 0; i < NR_CHUNKS; i++) 100 t->output += fio_crc16(buf, size); 101} 102 103static void t_crc7(struct test_type *t, void *buf, size_t size) 104{ 105 int i; 106 107 for (i = 0; i < NR_CHUNKS; i++) 108 t->output += fio_crc7(buf, size); 109} 110 111static void t_sha1(struct test_type *t, void *buf, size_t size) 112{ 113 uint32_t sha[5]; 114 struct fio_sha1_ctx ctx = { .H = sha }; 115 int i; 116 117 fio_sha1_init(&ctx); 118 119 for (i = 0; i < NR_CHUNKS; i++) { 120 fio_sha1_update(&ctx, buf, size); 121 fio_sha1_final(&ctx); 122 } 123} 124 125static void t_sha256(struct test_type *t, void *buf, size_t size) 126{ 127 uint8_t sha[64]; 128 struct fio_sha256_ctx ctx = { .buf = sha }; 129 int i; 130 131 fio_sha256_init(&ctx); 132 133 for (i = 0; i < NR_CHUNKS; i++) { 134 fio_sha256_update(&ctx, buf, size); 135 fio_sha256_final(&ctx); 136 } 137} 138 139static void t_sha512(struct test_type *t, void *buf, size_t size) 140{ 141 uint8_t sha[128]; 142 struct fio_sha512_ctx ctx = { .buf = sha }; 143 int i; 144 145 fio_sha512_init(&ctx); 146 147 for (i = 0; i < NR_CHUNKS; i++) 148 fio_sha512_update(&ctx, buf, size); 149} 150 151static void t_sha3_224(struct test_type *t, void *buf, size_t size) 152{ 153 uint8_t sha[SHA3_224_DIGEST_SIZE]; 154 struct fio_sha3_ctx ctx = { .sha = sha }; 155 int i; 156 157 fio_sha3_224_init(&ctx); 158 159 for (i = 0; i < NR_CHUNKS; i++) { 160 fio_sha3_update(&ctx, buf, size); 161 fio_sha3_final(&ctx); 162 } 163} 164 165static void t_sha3_256(struct test_type *t, void *buf, size_t size) 166{ 167 uint8_t sha[SHA3_256_DIGEST_SIZE]; 168 struct fio_sha3_ctx ctx = { .sha = sha }; 169 int i; 170 171 fio_sha3_256_init(&ctx); 172 173 for (i = 0; i < NR_CHUNKS; i++) { 174 fio_sha3_update(&ctx, buf, size); 175 fio_sha3_final(&ctx); 176 } 177} 178 179static void t_sha3_384(struct test_type *t, void *buf, size_t size) 180{ 181 uint8_t sha[SHA3_384_DIGEST_SIZE]; 182 struct fio_sha3_ctx ctx = { .sha = sha }; 183 int i; 184 185 fio_sha3_384_init(&ctx); 186 187 for (i = 0; i < NR_CHUNKS; i++) { 188 fio_sha3_update(&ctx, buf, size); 189 fio_sha3_final(&ctx); 190 } 191} 192 193static void t_sha3_512(struct test_type *t, void *buf, size_t size) 194{ 195 uint8_t sha[SHA3_512_DIGEST_SIZE]; 196 struct fio_sha3_ctx ctx = { .sha = sha }; 197 int i; 198 199 fio_sha3_512_init(&ctx); 200 201 for (i = 0; i < NR_CHUNKS; i++) { 202 fio_sha3_update(&ctx, buf, size); 203 fio_sha3_final(&ctx); 204 } 205} 206 207static void t_murmur3(struct test_type *t, void *buf, size_t size) 208{ 209 int i; 210 211 for (i = 0; i < NR_CHUNKS; i++) 212 t->output += murmurhash3(buf, size, 0x8989); 213} 214 215static void t_jhash(struct test_type *t, void *buf, size_t size) 216{ 217 int i; 218 219 for (i = 0; i < NR_CHUNKS; i++) 220 t->output += jhash(buf, size, 0x8989); 221} 222 223static void t_fnv(struct test_type *t, void *buf, size_t size) 224{ 225 int i; 226 227 for (i = 0; i < NR_CHUNKS; i++) 228 t->output += fnv(buf, size, 0x8989); 229} 230 231static void t_xxhash(struct test_type *t, void *buf, size_t size) 232{ 233 void *state; 234 int i; 235 236 state = XXH32_init(0x8989); 237 238 for (i = 0; i < NR_CHUNKS; i++) 239 XXH32_update(state, buf, size); 240 241 t->output = XXH32_digest(state); 242} 243 244static struct test_type t[] = { 245 { 246 .name = "md5", 247 .mask = T_MD5, 248 .fn = t_md5, 249 }, 250 { 251 .name = "crc64", 252 .mask = T_CRC64, 253 .fn = t_crc64, 254 }, 255 { 256 .name = "crc32", 257 .mask = T_CRC32, 258 .fn = t_crc32, 259 }, 260 { 261 .name = "crc32c", 262 .mask = T_CRC32C, 263 .fn = t_crc32c, 264 }, 265 { 266 .name = "crc16", 267 .mask = T_CRC16, 268 .fn = t_crc16, 269 }, 270 { 271 .name = "crc7", 272 .mask = T_CRC7, 273 .fn = t_crc7, 274 }, 275 { 276 .name = "sha1", 277 .mask = T_SHA1, 278 .fn = t_sha1, 279 }, 280 { 281 .name = "sha256", 282 .mask = T_SHA256, 283 .fn = t_sha256, 284 }, 285 { 286 .name = "sha512", 287 .mask = T_SHA512, 288 .fn = t_sha512, 289 }, 290 { 291 .name = "xxhash", 292 .mask = T_XXHASH, 293 .fn = t_xxhash, 294 }, 295 { 296 .name = "murmur3", 297 .mask = T_MURMUR3, 298 .fn = t_murmur3, 299 }, 300 { 301 .name = "jhash", 302 .mask = T_JHASH, 303 .fn = t_jhash, 304 }, 305 { 306 .name = "fnv", 307 .mask = T_FNV, 308 .fn = t_fnv, 309 }, 310 { 311 .name = "sha3-224", 312 .mask = T_SHA3_224, 313 .fn = t_sha3_224, 314 }, 315 { 316 .name = "sha3-256", 317 .mask = T_SHA3_256, 318 .fn = t_sha3_256, 319 }, 320 { 321 .name = "sha3-384", 322 .mask = T_SHA3_384, 323 .fn = t_sha3_384, 324 }, 325 { 326 .name = "sha3-512", 327 .mask = T_SHA3_512, 328 .fn = t_sha3_512, 329 }, 330 { 331 .name = NULL, 332 }, 333}; 334 335static unsigned int get_test_mask(const char *type) 336{ 337 char *ostr, *str = strdup(type); 338 unsigned int mask; 339 char *name; 340 int i; 341 342 ostr = str; 343 mask = 0; 344 while ((name = strsep(&str, ",")) != NULL) { 345 for (i = 0; t[i].name; i++) { 346 if (!strcmp(t[i].name, name)) { 347 mask |= t[i].mask; 348 break; 349 } 350 } 351 } 352 353 free(ostr); 354 return mask; 355} 356 357static int list_types(void) 358{ 359 int i; 360 361 for (i = 0; t[i].name; i++) 362 printf("%s\n", t[i].name); 363 364 return 1; 365} 366 367int fio_crctest(const char *type) 368{ 369 unsigned int test_mask = 0; 370 uint64_t mb = CHUNK * NR_CHUNKS; 371 struct frand_state state; 372 int i, first = 1; 373 void *buf; 374 375 crc32c_arm64_probe(); 376 crc32c_intel_probe(); 377 378 if (!type) 379 test_mask = ~0U; 380 else if (!strcmp(type, "help") || !strcmp(type, "list")) 381 return list_types(); 382 else 383 test_mask = get_test_mask(type); 384 385 if (!test_mask) { 386 fprintf(stderr, "fio: unknown hash `%s`. Available:\n", type); 387 return list_types(); 388 } 389 390 buf = malloc(CHUNK); 391 init_rand_seed(&state, 0x8989, 0); 392 fill_random_buf(&state, buf, CHUNK); 393 394 for (i = 0; t[i].name; i++) { 395 struct timeval tv; 396 double mb_sec; 397 uint64_t usec; 398 char pre[3]; 399 400 if (!(t[i].mask & test_mask)) 401 continue; 402 403 /* 404 * For first run, make sure CPUs are spun up and that 405 * we've touched the data. 406 */ 407 if (first) { 408 usec_spin(100000); 409 t[i].fn(&t[i], buf, CHUNK); 410 } 411 412 fio_gettime(&tv, NULL); 413 t[i].fn(&t[i], buf, CHUNK); 414 usec = utime_since_now(&tv); 415 416 if (usec) { 417 mb_sec = (double) mb / (double) usec; 418 mb_sec /= (1.024 * 1.024); 419 if (strlen(t[i].name) >= 7) 420 sprintf(pre, "\t"); 421 else 422 sprintf(pre, "\t\t"); 423 printf("%s:%s%8.2f MiB/sec\n", t[i].name, pre, mb_sec); 424 } else 425 printf("%s:inf MiB/sec\n", t[i].name); 426 first = 0; 427 } 428 429 free(buf); 430 return 0; 431} 432