04215a2f16028f0e3bcf7282ca5be463e1d47b40
[fio.git] / engines / guasi.c
1 /*
2  * guasi engine
3  *
4  * IO engine using the GUASI library.
5  *
6  * This is currently disabled, add -lguasi to the fio Makefile target
7  * and add a #define FIO_HAVE_GUASI to os-linux.h to enable it. You'll
8  * need the GUASI lib as well:
9  *
10  * http://www.xmailserver.org/guasi-lib.html
11  *
12  */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <assert.h>
18
19 #include "../fio.h"
20 #include "../os.h"
21
22 #ifdef FIO_HAVE_GUASI
23
24 #define GFIO_MIN_THREADS 32
25
26 #include <guasi.h>
27 #include <guasi_syscalls.h>
28
29 #ifdef GFIO_DEBUG
30 #define GDBG_PRINT(a) printf a
31 #else
32 #define GDBG_PRINT(a) (void) 0
33 #endif
34
35 #define STFU_GCC(a) a = a
36
37
38 struct guasi_data {
39         guasi_t hctx;
40         int max_reqs;
41         guasi_req_t *reqs;
42         struct io_u **io_us;
43         int reqs_nr;
44 };
45
46 static int fio_guasi_prep(struct thread_data fio_unused *td, struct io_u *io_u)
47 {
48         STFU_GCC(io_u);
49
50         GDBG_PRINT(("fio_guasi_prep(%p)\n", io_u));
51
52         return 0;
53 }
54
55 static struct io_u *fio_guasi_event(struct thread_data *td, int event)
56 {
57         struct guasi_data *ld = td->io_ops->data;
58         struct io_u *io_u;
59         struct guasi_reqinfo rinf;
60
61         GDBG_PRINT(("fio_guasi_event(%d)\n", event));
62         if (guasi_req_info(ld->reqs[event], &rinf) < 0) {
63                 fprintf(stderr, "guasi_req_info(%d) FAILED!\n", event);
64                 return NULL;
65         }
66         io_u = rinf.asid;
67         io_u->error = EINPROGRESS;
68         GDBG_PRINT(("fio_guasi_event(%d) -> %p\n", event, io_u));
69         if (rinf.status == GUASI_STATUS_COMPLETE) {
70                 io_u->error = rinf.result;
71                 if (io_u->ddir == DDIR_READ ||
72                     io_u->ddir == DDIR_WRITE) {
73                         io_u->error = 0;
74                         if (rinf.result != (long) io_u->xfer_buflen) {
75                                 if (rinf.result >= 0)
76                                         io_u->resid = io_u->xfer_buflen - rinf.result;
77                                 else
78                                         io_u->error = rinf.error;
79                         }
80                 }
81         }
82
83         return io_u;
84 }
85
86 static int fio_guasi_getevents(struct thread_data *td, int min, int max,
87                                struct timespec *t)
88 {
89         struct guasi_data *ld = td->io_ops->data;
90         int n = 0, r;
91         long timeo = -1;
92
93         GDBG_PRINT(("fio_guasi_getevents(%d, %d)\n", min, max));
94         if (min > ld->max_reqs)
95                 min = ld->max_reqs;
96         if (max > ld->max_reqs)
97                 max = ld->max_reqs;
98         if (t)
99                 timeo = t->tv_sec * 1000L + t->tv_nsec / 1000000L;
100         do {
101                 r = guasi_fetch(ld->hctx, ld->reqs + n, max - n, timeo);
102                 if (r < 0)
103                         break;
104                 n += r;
105                 if (n >= min)
106                         break;
107         } while (1);
108         GDBG_PRINT(("fio_guasi_getevents() -> %d\n", n));
109
110         return n;
111 }
112
113 static int fio_guasi_queue(struct thread_data *td, struct io_u *io_u)
114 {
115         struct guasi_data *ld = td->io_ops->data;
116
117         GDBG_PRINT(("fio_guasi_queue(%p)\n", io_u));
118         if (ld->reqs_nr == (int) td->iodepth)
119                 return FIO_Q_BUSY;
120
121         ld->io_us[ld->reqs_nr] = io_u;
122         ld->reqs_nr++;
123         return FIO_Q_QUEUED;
124 }
125
126 static void fio_guasi_queued(struct thread_data *td, struct io_u **io_us,
127                              unsigned int nr)
128 {
129         struct timeval now;
130         struct io_u *io_u = io_us[nr];
131
132         fio_gettime(&now, NULL);
133         memcpy(&io_u->issue_time, &now, sizeof(now));
134         io_u_queued(td, io_u);
135 }
136
137 static int fio_guasi_commit(struct thread_data *td)
138 {
139         struct guasi_data *ld = td->io_ops->data;
140         int i;
141         struct io_u *io_u;
142         struct fio_file *f;
143
144         GDBG_PRINT(("fio_guasi_commit()\n"));
145         for (i = 0; i < ld->reqs_nr; i++) {
146                 io_u = ld->io_us[i];
147                 f = io_u->file;
148                 io_u->greq = NULL;
149                 if (io_u->ddir == DDIR_READ)
150                         io_u->greq = guasi__pread(ld->hctx, ld, io_u, 0,
151                                                   f->fd, io_u->xfer_buf, io_u->xfer_buflen,
152                                                   io_u->offset);
153                 else if (io_u->ddir == DDIR_WRITE)
154                         io_u->greq = guasi__pwrite(ld->hctx, ld, io_u, 0,
155                                                    f->fd, io_u->xfer_buf, io_u->xfer_buflen,
156                                                    io_u->offset);
157                 else if (io_u->ddir == DDIR_SYNC)
158                         io_u->greq = guasi__fsync(ld->hctx, ld, io_u, 0, f->fd);
159                 else {
160                         fprintf(stderr, "fio_guasi_commit() FAILED: unknow request %d\n",
161                                 io_u->ddir);
162                 }
163                 if (io_u->greq != NULL)
164                         fio_guasi_queued(td, ld->io_us, i);
165         }
166         ld->reqs_nr = 0;
167         GDBG_PRINT(("fio_guasi_commit() -> %d\n", i));
168
169         return 0;
170 }
171
172 static int fio_guasi_cancel(struct thread_data *td, struct io_u *io_u)
173 {
174         struct guasi_data *ld = td->io_ops->data;
175
176         STFU_GCC(ld);
177         GDBG_PRINT(("fio_guasi_cancel(%p)\n", io_u));
178
179         return guasi_req_cancel(io_u->greq);
180 }
181
182 static void fio_guasi_cleanup(struct thread_data *td)
183 {
184         struct guasi_data *ld = td->io_ops->data;
185
186         if (ld) {
187                 guasi_free(ld->hctx);
188                 free(ld->reqs);
189                 free(ld->io_us);
190                 free(ld);
191                 td->io_ops->data = NULL;
192         }
193 }
194
195 static int fio_guasi_init(struct thread_data *td)
196 {
197         int maxthr;
198         struct guasi_data *ld = malloc(sizeof(*ld));
199
200         GDBG_PRINT(("fio_guasi_init(): depth=%d\n", td->iodepth));
201         memset(ld, 0, sizeof(*ld));
202         maxthr = td->iodepth > GFIO_MIN_THREADS ? td->iodepth: GFIO_MIN_THREADS;
203         if ((ld->hctx = guasi_create(GFIO_MIN_THREADS, maxthr, 1)) == NULL) {
204                 td_verror(td, errno, "guasi_create");
205                 free(ld);
206                 return 1;
207         }
208         ld->max_reqs = td->iodepth;
209         ld->reqs = malloc(ld->max_reqs * sizeof(guasi_req_t));
210         ld->io_us = malloc(ld->max_reqs * sizeof(struct io_u *));
211         memset(ld->io_us, 0, ld->max_reqs * sizeof(struct io_u *));
212         ld->reqs_nr = 0;
213
214         td->io_ops->data = ld;
215         GDBG_PRINT(("fio_guasi_init(): depth=%d -> %p\n", td->iodepth, ld));
216
217         return 0;
218 }
219
220 static struct ioengine_ops ioengine = {
221         .name           = "guasi",
222         .version        = FIO_IOOPS_VERSION,
223         .init           = fio_guasi_init,
224         .prep           = fio_guasi_prep,
225         .queue          = fio_guasi_queue,
226         .commit         = fio_guasi_commit,
227         .cancel         = fio_guasi_cancel,
228         .getevents      = fio_guasi_getevents,
229         .event          = fio_guasi_event,
230         .cleanup        = fio_guasi_cleanup,
231         .open_file      = generic_open_file,
232         .close_file     = generic_close_file,
233 };
234
235 #else /* FIO_HAVE_GUASI */
236
237 /*
238  * When we have a proper configure system in place, we simply wont build
239  * and install this io engine. For now install a crippled version that
240  * just complains and fails to load.
241  */
242 static int fio_guasi_init(struct thread_data fio_unused *td)
243 {
244         fprintf(stderr, "fio: guasi not available\n");
245         return 1;
246 }
247
248 static struct ioengine_ops ioengine = {
249         .name           = "guasi",
250         .version        = FIO_IOOPS_VERSION,
251         .init           = fio_guasi_init,
252 };
253
254 #endif
255
256 static void fio_init fio_guasi_register(void)
257 {
258         register_ioengine(&ioengine);
259 }
260
261 static void fio_exit fio_guasi_unregister(void)
262 {
263         unregister_ioengine(&ioengine);
264 }
265