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