bca46f243cf25077ddc4f43b596dc7fca2c19ab6
[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 }
117
118 static void t_sha256(struct test_type *t, void *buf, size_t size)
119 {
120         uint8_t sha[64];
121         struct fio_sha256_ctx ctx = { .buf = sha };
122         int i;
123
124         fio_sha256_init(&ctx);
125
126         for (i = 0; i < NR_CHUNKS; i++) {
127                 fio_sha256_update(&ctx, buf, size);
128                 fio_sha256_final(&ctx);
129         }
130 }
131
132 static void t_sha512(struct test_type *t, void *buf, size_t size)
133 {
134         uint8_t sha[128];
135         struct fio_sha512_ctx ctx = { .buf = sha };
136         int i;
137
138         fio_sha512_init(&ctx);
139
140         for (i = 0; i < NR_CHUNKS; i++)
141                 fio_sha512_update(&ctx, buf, size);
142 }
143
144 static void t_murmur3(struct test_type *t, void *buf, size_t size)
145 {
146         int i;
147
148         for (i = 0; i < NR_CHUNKS; i++)
149                 murmurhash3(buf, size, 0x8989);
150 }
151
152 static void t_jhash(struct test_type *t, void *buf, size_t size)
153 {
154         int i;
155
156         for (i = 0; i < NR_CHUNKS; i++)
157                 t->output += jhash(buf, size, 0x8989);
158 }
159
160 static void t_fnv(struct test_type *t, void *buf, size_t size)
161 {
162         int i;
163
164         for (i = 0; i < NR_CHUNKS; i++)
165                 t->output += fnv(buf, size, 0x8989);
166 }
167
168 static void t_xxhash(struct test_type *t, void *buf, size_t size)
169 {
170         void *state;
171         int i;
172
173         state = XXH32_init(0x8989);
174
175         for (i = 0; i < NR_CHUNKS; i++)
176                 XXH32_update(state, buf, size);
177
178         t->output = XXH32_digest(state);
179 }
180
181 static struct test_type t[] = {
182         {
183                 .name = "md5",
184                 .mask = T_MD5,
185                 .fn = t_md5,
186         },
187         {
188                 .name = "crc64",
189                 .mask = T_CRC64,
190                 .fn = t_crc64,
191         },
192         {
193                 .name = "crc32",
194                 .mask = T_CRC32,
195                 .fn = t_crc32,
196         },
197         {
198                 .name = "crc32c",
199                 .mask = T_CRC32C,
200                 .fn = t_crc32c,
201         },
202         {
203                 .name = "crc16",
204                 .mask = T_CRC16,
205                 .fn = t_crc16,
206         },
207         {
208                 .name = "crc7",
209                 .mask = T_CRC7,
210                 .fn = t_crc7,
211         },
212         {
213                 .name = "sha1",
214                 .mask = T_SHA1,
215                 .fn = t_sha1,
216         },
217         {
218                 .name = "sha256",
219                 .mask = T_SHA256,
220                 .fn = t_sha256,
221         },
222         {
223                 .name = "sha512",
224                 .mask = T_SHA512,
225                 .fn = t_sha512,
226         },
227         {
228                 .name = "xxhash",
229                 .mask = T_XXHASH,
230                 .fn = t_xxhash,
231         },
232         {
233                 .name = "murmur3",
234                 .mask = T_MURMUR3,
235                 .fn = t_murmur3,
236         },
237         {
238                 .name = "jhash",
239                 .mask = T_JHASH,
240                 .fn = t_jhash,
241         },
242         {
243                 .name = "fnv",
244                 .mask = T_FNV,
245                 .fn = t_fnv,
246         },
247         {
248                 .name = NULL,
249         },
250 };
251
252 static unsigned int get_test_mask(const char *type)
253 {
254         char *ostr, *str = strdup(type);
255         unsigned int mask;
256         char *name;
257         int i;
258
259         ostr = str;
260         mask = 0;
261         while ((name = strsep(&str, ",")) != NULL) {
262                 for (i = 0; t[i].name; i++) {
263                         if (!strcmp(t[i].name, name)) {
264                                 mask |= t[i].mask;
265                                 break;
266                         }
267                 }
268         }
269
270         free(ostr);
271         return mask;
272 }
273
274 static int list_types(void)
275 {
276         int i;
277
278         for (i = 0; t[i].name; i++)
279                 printf("%s\n", t[i].name);
280
281         return 1;
282 }
283
284 int fio_crctest(const char *type)
285 {
286         unsigned int test_mask = 0;
287         uint64_t mb = CHUNK * NR_CHUNKS;
288         struct frand_state state;
289         int i, first = 1;
290         void *buf;
291
292         crc32c_intel_probe();
293
294         if (!type)
295                 test_mask = ~0U;
296         else if (!strcmp(type, "help") || !strcmp(type, "list"))
297                 return list_types();
298         else
299                 test_mask = get_test_mask(type);
300
301         if (!test_mask) {
302                 fprintf(stderr, "fio: unknown hash `%s`. Available:\n", type);
303                 return list_types();
304         }
305
306         buf = malloc(CHUNK);
307         init_rand_seed(&state, 0x8989);
308         fill_random_buf(&state, buf, CHUNK);
309
310         for (i = 0; t[i].name; i++) {
311                 struct timeval tv;
312                 double mb_sec;
313                 uint64_t usec;
314                 char pre[3];
315
316                 if (!(t[i].mask & test_mask))
317                         continue;
318
319                 /*
320                  * For first run, make sure CPUs are spun up and that
321                  * we've touched the data.
322                  */
323                 if (first) {
324                         usec_spin(100000);
325                         t[i].fn(&t[i], buf, CHUNK);
326                 }
327
328                 fio_gettime(&tv, NULL);
329                 t[i].fn(&t[i], buf, CHUNK);
330                 usec = utime_since_now(&tv);
331
332                 mb_sec = (double) mb / (double) usec;
333                 mb_sec /= (1.024 * 1.024);
334                 if (strlen(t[i].name) >= 7)
335                         sprintf(pre, "\t");
336                 else
337                         sprintf(pre, "\t\t");
338                 printf("%s:%s%8.2f MB/sec\n", t[i].name, pre, mb_sec);
339                 first = 0;
340         }
341
342         free(buf);
343         return 0;
344 }