rdma ioengine improvement
[fio.git] / engines / sync.c
1 /*
2  * sync/psync engine
3  *
4  * IO engine that does regular read(2)/write(2) with lseek(2) to transfer
5  * data and IO engine that does regular pread(2)/pwrite(2) to transfer data.
6  *
7  */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <sys/uio.h>
12 #include <errno.h>
13 #include <assert.h>
14
15 #include "../fio.h"
16
17 struct syncio_data {
18         struct iovec *iovecs;
19         struct io_u **io_us;
20         unsigned int queued;
21         unsigned int events;
22         unsigned long queued_bytes;
23
24         unsigned long long last_offset;
25         struct fio_file *last_file;
26         enum fio_ddir last_ddir;
27 };
28
29 static int fio_syncio_prep(struct thread_data *td, struct io_u *io_u)
30 {
31         struct fio_file *f = io_u->file;
32
33         if (!ddir_rw(io_u->ddir))
34                 return 0;
35
36         if (f->file_pos != -1ULL && f->file_pos == io_u->offset)
37                 return 0;
38
39         if (lseek(f->fd, io_u->offset, SEEK_SET) == -1) {
40                 td_verror(td, errno, "lseek");
41                 return 1;
42         }
43
44         return 0;
45 }
46
47 static int fio_io_end(struct thread_data *td, struct io_u *io_u, int ret)
48 {
49         if (io_u->file && ret >= 0 && ddir_rw(io_u->ddir))
50                 io_u->file->file_pos = io_u->offset + ret;
51
52         if (ret != (int) io_u->xfer_buflen) {
53                 if (ret >= 0) {
54                         io_u->resid = io_u->xfer_buflen - ret;
55                         io_u->error = 0;
56                         return FIO_Q_COMPLETED;
57                 } else
58                         io_u->error = errno;
59         }
60
61         if (io_u->error)
62                 td_verror(td, io_u->error, "xfer");
63
64         return FIO_Q_COMPLETED;
65 }
66
67 static int fio_psyncio_queue(struct thread_data *td, struct io_u *io_u)
68 {
69         struct fio_file *f = io_u->file;
70         int ret;
71
72         fio_ro_check(td, io_u);
73
74         if (io_u->ddir == DDIR_READ)
75                 ret = pread(f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
76         else if (io_u->ddir == DDIR_WRITE)
77                 ret = pwrite(f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
78         else if (io_u->ddir == DDIR_TRIM) {
79                 do_io_u_trim(td, io_u);
80                 return FIO_Q_COMPLETED;
81         } else
82                 ret = do_io_u_sync(td, io_u);
83
84         return fio_io_end(td, io_u, ret);
85 }
86
87 static int fio_syncio_queue(struct thread_data *td, struct io_u *io_u)
88 {
89         struct fio_file *f = io_u->file;
90         int ret;
91
92         fio_ro_check(td, io_u);
93
94         if (io_u->ddir == DDIR_READ)
95                 ret = read(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
96         else if (io_u->ddir == DDIR_WRITE)
97                 ret = write(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
98         else if (io_u->ddir == DDIR_TRIM) {
99                 do_io_u_trim(td, io_u);
100                 return FIO_Q_COMPLETED;
101         } else
102                 ret = do_io_u_sync(td, io_u);
103
104         return fio_io_end(td, io_u, ret);
105 }
106
107 static int fio_vsyncio_getevents(struct thread_data *td, unsigned int min,
108                                  unsigned int max,
109                                  struct timespec fio_unused *t)
110 {
111         struct syncio_data *sd = td->io_ops->data;
112         int ret;
113
114         if (min) {
115                 ret = sd->events;
116                 sd->events = 0;
117         } else
118                 ret = 0;
119
120         dprint(FD_IO, "vsyncio_getevents: min=%d,max=%d: %d\n", min, max, ret);
121         return ret;
122 }
123
124 static struct io_u *fio_vsyncio_event(struct thread_data *td, int event)
125 {
126         struct syncio_data *sd = td->io_ops->data;
127
128         return sd->io_us[event];
129 }
130
131 static int fio_vsyncio_append(struct thread_data *td, struct io_u *io_u)
132 {
133         struct syncio_data *sd = td->io_ops->data;
134
135         if (ddir_sync(io_u->ddir))
136                 return 0;
137
138         if (io_u->offset == sd->last_offset && io_u->file == sd->last_file &&
139             io_u->ddir == sd->last_ddir)
140                 return 1;
141
142         return 0;
143 }
144
145 static void fio_vsyncio_set_iov(struct syncio_data *sd, struct io_u *io_u,
146                                 int idx)
147 {
148         sd->io_us[idx] = io_u;
149         sd->iovecs[idx].iov_base = io_u->xfer_buf;
150         sd->iovecs[idx].iov_len = io_u->xfer_buflen;
151         sd->last_offset = io_u->offset + io_u->xfer_buflen;
152         sd->last_file = io_u->file;
153         sd->last_ddir = io_u->ddir;
154         sd->queued_bytes += io_u->xfer_buflen;
155         sd->queued++;
156 }
157
158 static int fio_vsyncio_queue(struct thread_data *td, struct io_u *io_u)
159 {
160         struct syncio_data *sd = td->io_ops->data;
161
162         fio_ro_check(td, io_u);
163
164         if (!fio_vsyncio_append(td, io_u)) {
165                 dprint(FD_IO, "vsyncio_queue: no append (%d)\n", sd->queued);
166                 /*
167                  * If we can't append and have stuff queued, tell fio to
168                  * commit those first and then retry this io
169                  */
170                 if (sd->queued)
171                         return FIO_Q_BUSY;
172                 if (ddir_sync(io_u->ddir)) {
173                         int ret = do_io_u_sync(td, io_u);
174
175                         return fio_io_end(td, io_u, ret);
176                 }
177
178                 sd->queued = 0;
179                 sd->queued_bytes = 0;
180                 fio_vsyncio_set_iov(sd, io_u, 0);
181         } else {
182                 if (sd->queued == td->o.iodepth) {
183                         dprint(FD_IO, "vsyncio_queue: max depth %d\n", sd->queued);
184                         return FIO_Q_BUSY;
185                 }
186
187                 dprint(FD_IO, "vsyncio_queue: append\n");
188                 fio_vsyncio_set_iov(sd, io_u, sd->queued);
189         }
190
191         dprint(FD_IO, "vsyncio_queue: depth now %d\n", sd->queued);
192         return FIO_Q_QUEUED;
193 }
194
195 /*
196  * Check that we transferred all bytes, or saw an error, etc
197  */
198 static int fio_vsyncio_end(struct thread_data *td, ssize_t bytes)
199 {
200         struct syncio_data *sd = td->io_ops->data;
201         struct io_u *io_u;
202         unsigned int i;
203         int err;
204
205         /*
206          * transferred everything, perfect
207          */
208         if (bytes == sd->queued_bytes)
209                 return 0;
210
211         err = errno;
212         for (i = 0; i < sd->queued; i++) {
213                 io_u = sd->io_us[i];
214
215                 if (bytes == -1) {
216                         io_u->error = err;
217                 } else {
218                         unsigned int this_io;
219
220                         this_io = bytes;
221                         if (this_io > io_u->xfer_buflen)
222                                 this_io = io_u->xfer_buflen;
223
224                         io_u->resid = io_u->xfer_buflen - this_io;
225                         io_u->error = 0;
226                         bytes -= this_io;
227                 }
228         }
229
230         if (bytes == -1) {
231                 td_verror(td, err, "xfer vsync");
232                 return -err;
233         }
234
235         return 0;
236 }
237
238 static int fio_vsyncio_commit(struct thread_data *td)
239 {
240         struct syncio_data *sd = td->io_ops->data;
241         struct fio_file *f;
242         ssize_t ret;
243
244         if (!sd->queued)
245                 return 0;
246
247         io_u_mark_submit(td, sd->queued);
248         f = sd->last_file;
249
250         if (lseek(f->fd, sd->io_us[0]->offset, SEEK_SET) == -1) {
251                 int err = -errno;
252
253                 td_verror(td, errno, "lseek");
254                 return err;
255         }
256
257         if (sd->last_ddir == DDIR_READ)
258                 ret = readv(f->fd, sd->iovecs, sd->queued);
259         else
260                 ret = writev(f->fd, sd->iovecs, sd->queued);
261
262         dprint(FD_IO, "vsyncio_commit: %d\n", (int) ret);
263         sd->events = sd->queued;
264         sd->queued = 0;
265         return fio_vsyncio_end(td, ret);
266 }
267
268 static int fio_vsyncio_init(struct thread_data *td)
269 {
270         struct syncio_data *sd;
271
272         sd = malloc(sizeof(*sd));
273         memset(sd, 0, sizeof(*sd));
274         sd->last_offset = -1ULL;
275         sd->iovecs = malloc(td->o.iodepth * sizeof(struct iovec));
276         sd->io_us = malloc(td->o.iodepth * sizeof(struct io_u *));
277
278         td->io_ops->data = sd;
279         return 0;
280 }
281
282 static void fio_vsyncio_cleanup(struct thread_data *td)
283 {
284         struct syncio_data *sd = td->io_ops->data;
285
286         free(sd->iovecs);
287         free(sd->io_us);
288         free(sd);
289 }
290
291 static struct ioengine_ops ioengine_rw = {
292         .name           = "sync",
293         .version        = FIO_IOOPS_VERSION,
294         .prep           = fio_syncio_prep,
295         .queue          = fio_syncio_queue,
296         .open_file      = generic_open_file,
297         .close_file     = generic_close_file,
298         .get_file_size  = generic_get_file_size,
299         .flags          = FIO_SYNCIO,
300 };
301
302 static struct ioengine_ops ioengine_prw = {
303         .name           = "psync",
304         .version        = FIO_IOOPS_VERSION,
305         .queue          = fio_psyncio_queue,
306         .open_file      = generic_open_file,
307         .close_file     = generic_close_file,
308         .get_file_size  = generic_get_file_size,
309         .flags          = FIO_SYNCIO,
310 };
311
312 static struct ioengine_ops ioengine_vrw = {
313         .name           = "vsync",
314         .version        = FIO_IOOPS_VERSION,
315         .init           = fio_vsyncio_init,
316         .cleanup        = fio_vsyncio_cleanup,
317         .queue          = fio_vsyncio_queue,
318         .commit         = fio_vsyncio_commit,
319         .event          = fio_vsyncio_event,
320         .getevents      = fio_vsyncio_getevents,
321         .open_file      = generic_open_file,
322         .close_file     = generic_close_file,
323         .get_file_size  = generic_get_file_size,
324         .flags          = FIO_SYNCIO,
325 };
326
327 static void fio_init fio_syncio_register(void)
328 {
329         register_ioengine(&ioengine_rw);
330         register_ioengine(&ioengine_prw);
331         register_ioengine(&ioengine_vrw);
332 }
333
334 static void fio_exit fio_syncio_unregister(void)
335 {
336         unregister_ioengine(&ioengine_rw);
337         unregister_ioengine(&ioengine_prw);
338         unregister_ioengine(&ioengine_vrw);
339 }