Update to guasi 0.5 diff
[fio.git] / engines / guasi.c
... / ...
CommitLineData
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
38struct 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
46static 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
55static 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
86static 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
113static 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
126static 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
137static 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
172static 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
182static 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
195static 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
220static 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 */
242static int fio_guasi_init(struct thread_data fio_unused *td)
243{
244 fprintf(stderr, "fio: guasi not available\n");
245 return 1;
246}
247
248static struct ioengine_ops ioengine = {
249 .name = "guasi",
250 .version = FIO_IOOPS_VERSION,
251 .init = fio_guasi_init,
252};
253
254#endif
255
256static void fio_init fio_guasi_register(void)
257{
258 register_ioengine(&ioengine);
259}
260
261static void fio_exit fio_guasi_unregister(void)
262{
263 unregister_ioengine(&ioengine);
264}
265