8164ba0913e45880341c67c528a2cff2f0a1e0d6
[fio.git] / lib / memcpy.c
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
15 struct memcpy_test {
16         const char *name;
17         void *src;
18         void *dst;
19         size_t size;
20 };
21
22 static 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
72 struct memcpy_type {
73         const char *name;
74         unsigned int mask;
75         void (*fn)(struct memcpy_type *, struct memcpy_test *);
76 };
77
78 enum {
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
105 static void t_memcpy(struct memcpy_type *t, struct memcpy_test *test)
106 {
107         do_test(t, test, memcpy);
108 }
109
110 static void t_memmove(struct memcpy_type *t, struct memcpy_test *test)
111 {
112         do_test(t, test, memmove);
113 }
114
115 static 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
124 static void t_simple(struct memcpy_type *t, struct memcpy_test *test)
125 {
126         do_test(t, test, simple_memcpy);
127 }
128
129 static 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
151 static 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
173 static 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
183 static 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
207 static void free_tests(void)
208 {
209         free(tests[0].src);
210         free(tests[0].dst);
211 }
212
213 int 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 }