memcpy: use malloc
[fio.git] / lib / memcpy.c
... / ...
CommitLineData
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
190 src = malloc(BUF_SIZE);
191 dst = malloc(BUF_SIZE);
192 if (!src || !dst)
193 return 1;
194
195 init_rand_seed(&state, 0x8989, 0);
196 fill_random_buf(&state, src, BUF_SIZE);
197
198 for (i = 0; tests[i].name; i++) {
199 test = &tests[i];
200 test->src = src;
201 test->dst = dst;
202 }
203
204 return 0;
205}
206
207static void free_tests(void)
208{
209 free(tests[0].src);
210 free(tests[0].dst);
211}
212
213int fio_memcpy_test(const char *type)
214{
215 unsigned int test_mask = 0;
216 int j, i;
217
218 if (!type)
219 test_mask = ~0U;
220 else if (!strcmp(type, "help") || !strcmp(type, "list"))
221 return list_types();
222 else
223 test_mask = get_test_mask(type);
224
225 if (!test_mask) {
226 fprintf(stderr, "fio: unknown hash `%s`. Available:\n", type);
227 return list_types();
228 }
229
230 if (setup_tests()) {
231 fprintf(stderr, "setting up mem regions failed\n");
232 return 1;
233 }
234
235 for (i = 0; t[i].name; i++) {
236 struct timespec ts;
237 double mb_sec;
238 uint64_t usec;
239
240 if (!(t[i].mask & test_mask))
241 continue;
242
243 /*
244 * For first run, make sure CPUs are spun up and that
245 * we've touched the data.
246 */
247 usec_spin(100000);
248 t[i].fn(&t[i], &tests[0]);
249
250 printf("%s\n", t[i].name);
251
252 for (j = 0; tests[j].name; j++) {
253 fio_gettime(&ts, NULL);
254 t[i].fn(&t[i], &tests[j]);
255 usec = utime_since_now(&ts);
256
257 if (usec) {
258 unsigned long long mb = NR_ITERS * BUF_SIZE;
259
260 mb_sec = (double) mb / (double) usec;
261 mb_sec /= (1.024 * 1.024);
262 printf("\t%s:\t%8.2f MiB/sec\n", tests[j].name, mb_sec);
263 } else
264 printf("\t%s:inf MiB/sec\n", tests[j].name);
265 }
266 }
267
268 free_tests();
269 return 0;
270}