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