05ea73e69e1abee7d15e7a17ec0cd75da7cd01b8
[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 "../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, 0);
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 }