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