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