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