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