memcpy: free buffer in case of failure
[fio.git] / lib / memcpy.c
CommitLineData
b76d85a4
JA
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "memcpy.h"
6#include "rand.h"
7#include "../fio_time.h"
8#include "../gettime.h"
9#include "../fio.h"
10
11#define BUF_SIZE 32 * 1024 * 1024ULL
12
13#define NR_ITERS 64
14
15struct memcpy_test {
16 const char *name;
17 void *src;
18 void *dst;
19 size_t size;
20};
21
22static struct memcpy_test tests[] = {
23 {
24 .name = "8 bytes",
25 .size = 8,
26 },
27 {
28 .name = "16 bytes",
29 .size = 16,
30 },
31 {
32 .name = "96 bytes",
33 .size = 96,
34 },
35 {
36 .name = "128 bytes",
37 .size = 128,
38 },
39 {
40 .name = "256 bytes",
41 .size = 256,
42 },
43 {
44 .name = "512 bytes",
45 .size = 512,
46 },
47 {
48 .name = "2048 bytes",
49 .size = 2048,
50 },
51 {
52 .name = "8192 bytes",
53 .size = 8192,
54 },
55 {
56 .name = "131072 bytes",
57 .size = 131072,
58 },
59 {
60 .name = "262144 bytes",
61 .size = 262144,
62 },
63 {
64 .name = "524288 bytes",
65 .size = 524288,
66 },
67 {
68 .name = NULL,
69 },
70};
71
72struct memcpy_type {
73 const char *name;
74 unsigned int mask;
75 void (*fn)(struct memcpy_type *, struct memcpy_test *);
76};
77
78enum {
79 T_MEMCPY = 1U << 0,
80 T_MEMMOVE = 1U << 1,
81 T_SIMPLE = 1U << 2,
82};
83
84#define do_test(t, test, fn) do { \
85 size_t left, this; \
86 void *src, *dst; \
87 int i; \
88 \
89 for (i = 0; i < NR_ITERS; i++) { \
90 left = BUF_SIZE; \
91 src = test->src; \
92 dst = test->dst; \
93 while (left) { \
94 this = test->size; \
95 if (this > left) \
96 this = left; \
97 (fn)(dst, src, this); \
98 left -= this; \
99 src += this; \
100 dst += this; \
101 } \
102 } \
103} while (0)
104
105static void t_memcpy(struct memcpy_type *t, struct memcpy_test *test)
106{
107 do_test(t, test, memcpy);
108}
109
110static void t_memmove(struct memcpy_type *t, struct memcpy_test *test)
111{
112 do_test(t, test, memmove);
113}
114
115static void simple_memcpy(void *dst, void const *src, size_t len)
116{
117 char *d = dst;
118 const char *s = src;
119
120 while (len--)
121 *d++ = *s++;
122}
123
124static void t_simple(struct memcpy_type *t, struct memcpy_test *test)
125{
126 do_test(t, test, simple_memcpy);
127}
128
129static struct memcpy_type t[] = {
130 {
131 .name = "memcpy",
132 .mask = T_MEMCPY,
133 .fn = t_memcpy,
134 },
135 {
136 .name = "memmove",
137 .mask = T_MEMMOVE,
138 .fn = t_memmove,
139 },
140 {
141 .name = "simple",
142 .mask = T_SIMPLE,
143 .fn = t_simple,
144 },
145
146 {
147 .name = NULL,
148 },
149};
150
151static unsigned int get_test_mask(const char *type)
152{
153 char *ostr, *str = strdup(type);
154 unsigned int mask;
155 char *name;
156 int i;
157
158 ostr = str;
159 mask = 0;
160 while ((name = strsep(&str, ",")) != NULL) {
161 for (i = 0; t[i].name; i++) {
162 if (!strcmp(t[i].name, name)) {
163 mask |= t[i].mask;
164 break;
165 }
166 }
167 }
168
169 free(ostr);
170 return mask;
171}
172
173static int list_types(void)
174{
175 int i;
176
177 for (i = 0; t[i].name; i++)
178 printf("%s\n", t[i].name);
179
180 return 1;
181}
182
183static int setup_tests(void)
184{
185 struct memcpy_test *test;
186 struct frand_state state;
187 void *src, *dst;
188 int i;
189
2226ce34
JA
190 src = malloc(BUF_SIZE);
191 dst = malloc(BUF_SIZE);
3436e74b
JA
192 if (!src || !dst) {
193 free(src);
194 free(dst);
b76d85a4 195 return 1;
3436e74b 196 }
b76d85a4
JA
197
198 init_rand_seed(&state, 0x8989, 0);
199 fill_random_buf(&state, src, BUF_SIZE);
200
201 for (i = 0; tests[i].name; i++) {
202 test = &tests[i];
203 test->src = src;
204 test->dst = dst;
205 }
206
207 return 0;
208}
209
2226ce34
JA
210static void free_tests(void)
211{
212 free(tests[0].src);
213 free(tests[0].dst);
214}
215
b76d85a4
JA
216int fio_memcpy_test(const char *type)
217{
218 unsigned int test_mask = 0;
219 int j, i;
220
221 if (!type)
222 test_mask = ~0U;
223 else if (!strcmp(type, "help") || !strcmp(type, "list"))
224 return list_types();
225 else
226 test_mask = get_test_mask(type);
227
228 if (!test_mask) {
229 fprintf(stderr, "fio: unknown hash `%s`. Available:\n", type);
230 return list_types();
231 }
232
233 if (setup_tests()) {
234 fprintf(stderr, "setting up mem regions failed\n");
235 return 1;
236 }
237
238 for (i = 0; t[i].name; i++) {
239 struct timespec ts;
240 double mb_sec;
241 uint64_t usec;
242
243 if (!(t[i].mask & test_mask))
244 continue;
245
246 /*
247 * For first run, make sure CPUs are spun up and that
248 * we've touched the data.
249 */
250 usec_spin(100000);
251 t[i].fn(&t[i], &tests[0]);
252
253 printf("%s\n", t[i].name);
254
255 for (j = 0; tests[j].name; j++) {
256 fio_gettime(&ts, NULL);
257 t[i].fn(&t[i], &tests[j]);
258 usec = utime_since_now(&ts);
259
260 if (usec) {
261 unsigned long long mb = NR_ITERS * BUF_SIZE;
262
263 mb_sec = (double) mb / (double) usec;
264 mb_sec /= (1.024 * 1.024);
265 printf("\t%s:\t%8.2f MiB/sec\n", tests[j].name, mb_sec);
266 } else
267 printf("\t%s:inf MiB/sec\n", tests[j].name);
268 }
269 }
270
2226ce34 271 free_tests();
b76d85a4
JA
272 return 0;
273}