Home | History | Annotate | Download | only in crc
      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