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