X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=engines%2Fwindowsaio.c;h=13d7f19402a1759fa8c28f7e11b6e13686098e93;hp=5c7e79643aaf35978d62919455c235fbb3f41260;hb=HEAD;hpb=1dd90eec6cf5e68285dcab638b97a25f5f3018d4 diff --git a/engines/windowsaio.c b/engines/windowsaio.c index 5c7e7964..6681f8bb 100644 --- a/engines/windowsaio.c +++ b/engines/windowsaio.c @@ -11,6 +11,7 @@ #include #include "../fio.h" +#include "../optgroup.h" typedef BOOL (WINAPI *CANCELIOEX)(HANDLE hFile, LPOVERLAPPED lpOverlapped); @@ -35,6 +36,26 @@ struct thread_ctx { struct windowsaio_data *wd; }; +struct windowsaio_options { + struct thread_data *td; + unsigned int no_completion_thread; +}; + +static struct fio_option options[] = { + { + .name = "no_completion_thread", + .lname = "No completion polling thread", + .type = FIO_OPT_STR_SET, + .off1 = offsetof(struct windowsaio_options, no_completion_thread), + .help = "Use to avoid separate completion polling thread", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_WINDOWSAIO, + }, + { + .name = NULL, + }, +}; + static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter); static int fio_windowsaio_init(struct thread_data *td) @@ -80,6 +101,7 @@ static int fio_windowsaio_init(struct thread_data *td) struct thread_ctx *ctx; struct windowsaio_data *wd; HANDLE hFile; + struct windowsaio_options *o = td->eo; hFile = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (hFile == INVALID_HANDLE_VALUE) { @@ -91,29 +113,30 @@ static int fio_windowsaio_init(struct thread_data *td) wd->iothread_running = TRUE; wd->iocp = hFile; - if (!rc) - ctx = malloc(sizeof(struct thread_ctx)); + if (o->no_completion_thread == 0) { + if (!rc) + ctx = malloc(sizeof(struct thread_ctx)); - if (!rc && ctx == NULL) { - log_err("windowsaio: failed to allocate memory for thread context structure\n"); - CloseHandle(hFile); - rc = 1; - } + if (!rc && ctx == NULL) { + log_err("windowsaio: failed to allocate memory for thread context structure\n"); + CloseHandle(hFile); + rc = 1; + } - if (!rc) { - DWORD threadid; + if (!rc) { + DWORD threadid; - ctx->iocp = hFile; - ctx->wd = wd; - wd->iothread = CreateThread(NULL, 0, IoCompletionRoutine, ctx, 0, &threadid); - if (!wd->iothread) - log_err("windowsaio: failed to create io completion thread\n"); - else if (fio_option_is_set(&td->o, cpumask)) - fio_setaffinity(threadid, td->o.cpumask); + ctx->iocp = hFile; + ctx->wd = wd; + wd->iothread = CreateThread(NULL, 0, IoCompletionRoutine, ctx, 0, &threadid); + if (!wd->iothread) + log_err("windowsaio: failed to create io completion thread\n"); + else if (fio_option_is_set(&td->o, cpumask)) + fio_setaffinity(threadid, td->o.cpumask); + } + if (rc || wd->iothread == NULL) + rc = 1; } - - if (rc || wd->iothread == NULL) - rc = 1; } return rc; @@ -161,15 +184,15 @@ static int windowsaio_invalidate_cache(struct fio_file *f) if (ihFile != INVALID_HANDLE_VALUE) { if (!CloseHandle(ihFile)) { error = GetLastError(); - log_info("windowsaio: invalidation fd close %s " - "failed: error %d\n", f->file_name, error); + log_info("windowsaio: invalidation fd close %s failed: error %lu\n", + f->file_name, error); rc = 1; } } else { error = GetLastError(); if (error != ERROR_FILE_NOT_FOUND) { - log_info("windowsaio: cache invalidation of %s failed: " - "error %d\n", f->file_name, error); + log_info("windowsaio: cache invalidation of %s failed: error %lu\n", + f->file_name, error); rc = 1; } } @@ -225,7 +248,7 @@ static int fio_windowsaio_open_file(struct thread_data *td, struct fio_file *f) log_err("fio: unknown fadvise type %d\n", td->o.fadvise_hint); } - if (!td_write(td) || read_only) + if ((!td_write(td) && !(td->flags & TD_F_SYNCS)) || read_only) access = GENERIC_READ; else access = (GENERIC_READ | GENERIC_WRITE); @@ -302,9 +325,63 @@ static struct io_u* fio_windowsaio_event(struct thread_data *td, int event) return wd->aio_events[event]; } -static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min, - unsigned int max, - const struct timespec *t) +/* dequeue completion entrees directly (no separate completion thread) */ +static int fio_windowsaio_getevents_nothread(struct thread_data *td, unsigned int min, + unsigned int max, const struct timespec *t) +{ + struct windowsaio_data *wd = td->io_ops_data; + unsigned int dequeued = 0; + struct io_u *io_u; + DWORD start_count = 0; + DWORD end_count = 0; + DWORD mswait = 250; + struct fio_overlapped *fov; + + if (t != NULL) { + mswait = (t->tv_sec * 1000) + (t->tv_nsec / 1000000); + start_count = GetTickCount(); + end_count = start_count + (t->tv_sec * 1000) + (t->tv_nsec / 1000000); + } + + do { + BOOL ret; + OVERLAPPED *ovl; + + ULONG entries = min(16, max-dequeued); + OVERLAPPED_ENTRY oe[16]; + ret = GetQueuedCompletionStatusEx(wd->iocp, oe, 16, &entries, mswait, 0); + if (ret && entries) { + int entry_num; + + for (entry_num=0; entry_numio_u; + + if (ovl->Internal == ERROR_SUCCESS) { + io_u->resid = io_u->xfer_buflen - ovl->InternalHigh; + io_u->error = 0; + } else { + io_u->resid = io_u->xfer_buflen; + io_u->error = win_to_posix_error(GetLastError()); + } + + fov->io_complete = FALSE; + wd->aio_events[dequeued] = io_u; + dequeued++; + } + } + + if (dequeued >= min || + (t != NULL && timeout_expired(start_count, end_count))) + break; + } while (1); + return dequeued; +} + +/* dequeue completion entrees creates by separate IoCompletionRoutine thread */ +static int fio_windowaio_getevents_thread(struct thread_data *td, unsigned int min, + unsigned int max, const struct timespec *t) { struct windowsaio_data *wd = td->io_ops_data; unsigned int dequeued = 0; @@ -334,7 +411,6 @@ static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min, wd->aio_events[dequeued] = io_u; dequeued++; } - } if (dequeued >= min) break; @@ -353,6 +429,16 @@ static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min, return dequeued; } +static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min, + unsigned int max, const struct timespec *t) +{ + struct windowsaio_options *o = td->eo; + + if (o->no_completion_thread) + return fio_windowsaio_getevents_nothread(td, min, max, t); + return fio_windowaio_getevents_thread(td, min, max, t); +} + static enum fio_q_status fio_windowsaio_queue(struct thread_data *td, struct io_u *io_u) { @@ -484,6 +570,8 @@ static struct ioengine_ops ioengine = { .get_file_size = generic_get_file_size, .io_u_init = fio_windowsaio_io_u_init, .io_u_free = fio_windowsaio_io_u_free, + .options = options, + .option_struct_size = sizeof(struct windowsaio_options), }; static void fio_init fio_windowsaio_register(void)